@topconsultnpm/sdkui-react 6.21.0-dev2.9 → 6.21.0-t2
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.
- package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +4 -4
- package/lib/components/base/TMAccordionNew.js +1 -0
- package/lib/components/base/TMAreaManager.js +19 -3
- package/lib/components/base/TMDataGrid.js +2 -2
- package/lib/components/base/TMModal.d.ts +1 -0
- package/lib/components/base/TMModal.js +2 -2
- package/lib/components/base/TMPanel.d.ts +7 -4
- package/lib/components/base/TMPanel.js +58 -26
- package/lib/components/base/TMTreeView.js +12 -2
- package/lib/components/base/TMWaitPanel.js +7 -4
- package/lib/components/choosers/TMDistinctValues.js +35 -21
- package/lib/components/choosers/TMUserChooser.d.ts +4 -0
- package/lib/components/choosers/TMUserChooser.js +7 -5
- package/lib/components/editors/TMFormulaEditor.d.ts +2 -0
- package/lib/components/editors/TMFormulaEditor.js +75 -21
- package/lib/components/editors/TMMetadataValues.js +2 -1
- package/lib/components/editors/TMRadioButton.js +7 -5
- package/lib/components/editors/TMTextBox.d.ts +2 -0
- package/lib/components/editors/TMTextBox.js +3 -3
- package/lib/components/features/archive/TMArchive.js +1 -1
- package/lib/components/features/documents/TMCopyToFolderForm.d.ts +24 -0
- package/lib/components/features/documents/TMCopyToFolderForm.js +379 -0
- package/lib/components/features/documents/TMDcmtForm.d.ts +1 -0
- package/lib/components/features/documents/TMDcmtForm.js +107 -29
- package/lib/components/features/documents/TMDcmtPreview.d.ts +1 -0
- package/lib/components/features/documents/TMDcmtPreview.js +2 -2
- package/lib/components/features/documents/TMDcmtTasks.d.ts +1 -0
- package/lib/components/features/documents/TMDcmtTasks.js +2 -2
- package/lib/components/features/documents/TMDownloadRelationViewerSection.d.ts +23 -0
- package/lib/components/features/documents/TMDownloadRelationViewerSection.js +173 -0
- package/lib/components/features/documents/TMFileUploader.js +1 -1
- package/lib/components/features/documents/TMMasterDetailDcmts.d.ts +4 -0
- package/lib/components/features/documents/TMMasterDetailDcmts.js +29 -9
- package/lib/components/features/documents/TMMergeToPdfForm.d.ts +26 -0
- package/lib/components/features/documents/TMMergeToPdfForm.js +293 -0
- package/lib/components/features/documents/TMRelationViewer.d.ts +13 -0
- package/lib/components/features/documents/TMRelationViewer.js +75 -6
- package/lib/components/features/documents/copyAndMergeDcmtsShared.d.ts +71 -0
- package/lib/components/features/documents/copyAndMergeDcmtsShared.js +304 -0
- package/lib/components/features/search/SignatureParamsManager.d.ts +70 -0
- package/lib/components/features/search/SignatureParamsManager.js +145 -0
- package/lib/components/features/search/TMSavedQuerySelector.d.ts +2 -2
- package/lib/components/features/search/TMSavedQuerySelector.js +3 -2
- package/lib/components/features/search/TMSearch.d.ts +6 -1
- package/lib/components/features/search/TMSearch.js +16 -10
- package/lib/components/features/search/TMSearchQueryPanel.js +1 -1
- package/lib/components/features/search/TMSearchResult.d.ts +4 -0
- package/lib/components/features/search/TMSearchResult.js +118 -22
- package/lib/components/features/workflow/diagram/queryDescriptorParser.js +3 -6
- package/lib/components/forms/Login/TMLoginForm.d.ts +9 -0
- package/lib/components/forms/Login/TMLoginForm.js +61 -0
- package/lib/components/forms/TMResultDialog.d.ts +1 -1
- package/lib/components/forms/TMResultDialog.js +4 -2
- package/lib/components/index.d.ts +1 -0
- package/lib/components/index.js +1 -0
- package/lib/components/pages/TMPage.js +3 -1
- package/lib/components/query/TMQueryEditor.js +1 -1
- package/lib/components/viewers/TMTidViewer.js +1 -1
- package/lib/helper/SDKUI_Globals.d.ts +15 -0
- package/lib/helper/SDKUI_Globals.js +15 -1
- package/lib/helper/SDKUI_Localizator.d.ts +106 -2
- package/lib/helper/SDKUI_Localizator.js +1060 -12
- package/lib/helper/TMPdfViewer.js +25 -24
- package/lib/helper/TMUtils.d.ts +20 -0
- package/lib/helper/TMUtils.js +17 -0
- package/lib/helper/ZipManager.d.ts +56 -0
- package/lib/helper/ZipManager.js +127 -0
- package/lib/helper/index.d.ts +1 -0
- package/lib/helper/index.js +1 -0
- package/lib/hooks/useDataUserIdItem.js +6 -4
- package/lib/hooks/useDcmtOperations.d.ts +9 -2
- package/lib/hooks/useDcmtOperations.js +77 -34
- package/lib/hooks/useDocumentOperations.d.ts +5 -0
- package/lib/hooks/useDocumentOperations.js +238 -27
- package/lib/hooks/useForm.js +5 -2
- package/lib/hooks/useResizeObserver.d.ts +1 -1
- package/lib/hooks/useResizeObserver.js +16 -15
- package/package.json +3 -2
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DcmtInfo } from '../../../ts';
|
|
3
|
+
import { DocumentDownloadSettings, FileNamingMode } from '../../../helper';
|
|
4
|
+
import { IRelatedDcmt } from './TMMasterDetailDcmts';
|
|
5
|
+
/** Numero minimo di file PDF necessari per poterli unire in un unico documento. */
|
|
6
|
+
export declare const MIN_PDF_FOR_MERGE = 2;
|
|
7
|
+
/** Stile per le etichette "floating" posizionate sopra i bordi dei container */
|
|
8
|
+
export declare const getFloatingLabelStyle: () => React.CSSProperties;
|
|
9
|
+
/** Chiave univoca per un IRelatedDcmt basata sulla coppia tid+did */
|
|
10
|
+
export declare const getDcmtKey: (item: IRelatedDcmt) => string;
|
|
11
|
+
/** Deduplica gli IRelatedDcmt in base alla coppia tid+did (mantiene la prima occorrenza) */
|
|
12
|
+
export declare const dedupeByTidDid: (items: ReadonlyArray<IRelatedDcmt>) => Array<IRelatedDcmt>;
|
|
13
|
+
/** Verifica se showDirectoryPicker è supportato (Chrome, Edge) */
|
|
14
|
+
export declare const isDirectoryPickerSupported: () => boolean;
|
|
15
|
+
/**
|
|
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.
|
|
20
|
+
*/
|
|
21
|
+
export declare const isPdfExt: (ext: string | null | undefined) => boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Estrae l'estensione completa da un nome file, gestendo estensioni composite
|
|
24
|
+
* a più livelli come .PDF.P7M, .XML.P7M.TS, etc.
|
|
25
|
+
*
|
|
26
|
+
* Esempi:
|
|
27
|
+
* - "documento.pdf" -> ".pdf"
|
|
28
|
+
* - "DCMT_123.PDF.P7M" -> ".PDF.P7M"
|
|
29
|
+
* - "fattura.xml.p7m" -> ".xml.p7m"
|
|
30
|
+
* - "example.XML.P7M.TS" -> ".XML.P7M.TS"
|
|
31
|
+
* - "file.tar.gz" -> ".gz" (tar.gz non è gestito come firma)
|
|
32
|
+
* - "file" -> ""
|
|
33
|
+
*/
|
|
34
|
+
export declare const getFullFileExtension: (fileName: string, depth?: number) => string;
|
|
35
|
+
/**
|
|
36
|
+
* Estrae il nome base del file (senza estensione completa).
|
|
37
|
+
* Gestisce estensioni composite come .PDF.P7M
|
|
38
|
+
*/
|
|
39
|
+
export declare const getFileBaseName: (fileName: string) => string;
|
|
40
|
+
/** Sanitizza il nome file per Windows (rimuove caratteri illegali e limita la lunghezza) */
|
|
41
|
+
export declare const sanitizeFileName: (fileName: string, fallbackName: string, maxLength?: number) => string;
|
|
42
|
+
/** Verifica se un file esiste nella cartella (FileSystemDirectoryHandle) */
|
|
43
|
+
export declare const fileExists: (dirHandle: FileSystemDirectoryHandle, fileName: string) => Promise<boolean>;
|
|
44
|
+
/** Genera un nome file univoco aggiungendo un suffisso numerico se già esistente */
|
|
45
|
+
export declare const generateUniqueFileName: (dirHandle: FileSystemDirectoryHandle, originalName: string) => Promise<string>;
|
|
46
|
+
/** Recupera il nome leggibile del tipo documento (cache) */
|
|
47
|
+
export declare const getTypeName: (tid: number | undefined) => Promise<string>;
|
|
48
|
+
/** Formatta un valore convertendo le date in formato dd-MM-yyyy [HH-mm-ss] */
|
|
49
|
+
export declare const formatMetadataValue: (value: string) => string;
|
|
50
|
+
/** Recupera i metadati filtrati (primi 5 con mid > 100 e valore presente), concatenati con separatorChar */
|
|
51
|
+
export declare const getFilteredMetadata: (tid: number, did: number, separatorChar: string) => Promise<string | null>;
|
|
52
|
+
/** Opzioni di naming necessarie per generare il nome del file di destinazione */
|
|
53
|
+
export interface IFileNamingOptions {
|
|
54
|
+
fileNamingMode: FileNamingMode;
|
|
55
|
+
separatorChar: string;
|
|
56
|
+
}
|
|
57
|
+
/** Genera il nome file di destinazione in base alle impostazioni di naming */
|
|
58
|
+
export declare const generateTargetFileName: (file: File, dcmtInfo: DcmtInfo, options: IFileNamingOptions) => Promise<string>;
|
|
59
|
+
/**
|
|
60
|
+
* Restituisce i documenti da scaricare:
|
|
61
|
+
* - se è visibile il TMRelationViewer, usa gli isDcmt selezionati al suo interno
|
|
62
|
+
* - altrimenti restituisce i selectedDcmtInfos passati come prop
|
|
63
|
+
*/
|
|
64
|
+
export declare const getDcmtInfosToDownload: (selectedDcmtInfos: Array<DcmtInfo>, selectedItemsRelationViewer: Array<IRelatedDcmt>, showTMRelationViewer: boolean) => Array<DcmtInfo>;
|
|
65
|
+
/**
|
|
66
|
+
* Costruisce lo stato iniziale di DocumentDownloadSettings combinando:
|
|
67
|
+
* - i valori salvati in userSettings (se presenti)
|
|
68
|
+
* - i default della classe
|
|
69
|
+
* Nota: destinationFolder e zipPassword vengono sempre resettati per sicurezza.
|
|
70
|
+
*/
|
|
71
|
+
export declare const buildInitialDownloadSettings: (saved: DocumentDownloadSettings | undefined, defaultInvoiceFormat: DocumentDownloadSettings["invoiceFormat"], defaultOrderFormat: DocumentDownloadSettings["orderFormat"]) => DocumentDownloadSettings;
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { DcmtTypeListCacheService, LayoutModes, SDK_Globals } from '@topconsultnpm/sdk-ts';
|
|
2
|
+
import { searchResultToMetadataValues, DocumentDownloadSettings } from '../../../helper';
|
|
3
|
+
import { TMColors } from '../../../utils/theme';
|
|
4
|
+
/** Numero minimo di file PDF necessari per poterli unire in un unico documento. */
|
|
5
|
+
export const MIN_PDF_FOR_MERGE = 2;
|
|
6
|
+
// ============================================================
|
|
7
|
+
// Stili comuni
|
|
8
|
+
// ============================================================
|
|
9
|
+
/** Stile per le etichette "floating" posizionate sopra i bordi dei container */
|
|
10
|
+
export const getFloatingLabelStyle = () => ({
|
|
11
|
+
position: 'absolute',
|
|
12
|
+
top: '-10px',
|
|
13
|
+
left: '12px',
|
|
14
|
+
maxWidth: 'calc(100% - 24px)',
|
|
15
|
+
fontSize: '0.85rem',
|
|
16
|
+
fontWeight: 600,
|
|
17
|
+
color: TMColors.primary,
|
|
18
|
+
padding: '0 8px',
|
|
19
|
+
backgroundColor: 'white',
|
|
20
|
+
zIndex: 1,
|
|
21
|
+
whiteSpace: 'nowrap',
|
|
22
|
+
overflow: 'hidden',
|
|
23
|
+
textOverflow: 'ellipsis',
|
|
24
|
+
display: 'inline-block',
|
|
25
|
+
width: 'fit-content',
|
|
26
|
+
lineHeight: '20px',
|
|
27
|
+
letterSpacing: '0.2px',
|
|
28
|
+
boxSizing: 'border-box'
|
|
29
|
+
});
|
|
30
|
+
// ============================================================
|
|
31
|
+
// Helper su IRelatedDcmt
|
|
32
|
+
// ============================================================
|
|
33
|
+
/** Chiave univoca per un IRelatedDcmt basata sulla coppia tid+did */
|
|
34
|
+
export const getDcmtKey = (item) => `${item.tid ?? ''}_${item.did ?? ''}`;
|
|
35
|
+
/** Deduplica gli IRelatedDcmt in base alla coppia tid+did (mantiene la prima occorrenza) */
|
|
36
|
+
export const dedupeByTidDid = (items) => {
|
|
37
|
+
const map = new Map();
|
|
38
|
+
for (const item of items) {
|
|
39
|
+
const key = getDcmtKey(item);
|
|
40
|
+
if (!map.has(key))
|
|
41
|
+
map.set(key, item);
|
|
42
|
+
}
|
|
43
|
+
return Array.from(map.values());
|
|
44
|
+
};
|
|
45
|
+
// ============================================================
|
|
46
|
+
// Feature detection / Estensioni file
|
|
47
|
+
// ============================================================
|
|
48
|
+
/** Verifica se showDirectoryPicker è supportato (Chrome, Edge) */
|
|
49
|
+
export const isDirectoryPickerSupported = () => {
|
|
50
|
+
return 'showDirectoryPicker' in window;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
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.
|
|
57
|
+
*/
|
|
58
|
+
export const isPdfExt = (ext) => {
|
|
59
|
+
if (!ext)
|
|
60
|
+
return false;
|
|
61
|
+
const normalized = ext.trim().toLowerCase().replace(/^\./, '');
|
|
62
|
+
return normalized === 'pdf' || normalized === 'pdf.p7m' || normalized === 'pdf.tsd' || normalized === 'pdf.m7m';
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Estensioni di firma/marca temporale note che possono avvolgere altre estensioni.
|
|
66
|
+
* Es: file.pdf.p7m, file.xml.p7m, file.docx.p7m, file.xml.p7m.ts
|
|
67
|
+
*/
|
|
68
|
+
const SIGNATURE_EXTENSIONS = new Set(['p7m', 'p7s', 'm7m', 'tsd', 'tsr', 'ts']);
|
|
69
|
+
/** Profondità massima di ricorsione per la ricerca di estensioni composite */
|
|
70
|
+
const MAX_EXTENSION_DEPTH = 5;
|
|
71
|
+
/**
|
|
72
|
+
* Estrae l'estensione completa da un nome file, gestendo estensioni composite
|
|
73
|
+
* a più livelli come .PDF.P7M, .XML.P7M.TS, etc.
|
|
74
|
+
*
|
|
75
|
+
* Esempi:
|
|
76
|
+
* - "documento.pdf" -> ".pdf"
|
|
77
|
+
* - "DCMT_123.PDF.P7M" -> ".PDF.P7M"
|
|
78
|
+
* - "fattura.xml.p7m" -> ".xml.p7m"
|
|
79
|
+
* - "example.XML.P7M.TS" -> ".XML.P7M.TS"
|
|
80
|
+
* - "file.tar.gz" -> ".gz" (tar.gz non è gestito come firma)
|
|
81
|
+
* - "file" -> ""
|
|
82
|
+
*/
|
|
83
|
+
export const getFullFileExtension = (fileName, depth = 0) => {
|
|
84
|
+
if (!fileName || depth > MAX_EXTENSION_DEPTH)
|
|
85
|
+
return '';
|
|
86
|
+
const lastDotIndex = fileName.lastIndexOf('.');
|
|
87
|
+
if (lastDotIndex <= 0)
|
|
88
|
+
return '';
|
|
89
|
+
const lastExtension = fileName.substring(lastDotIndex + 1).toLowerCase();
|
|
90
|
+
// Se l'ultima estensione è una firma/marca, cerca ricorsivamente le estensioni precedenti
|
|
91
|
+
if (SIGNATURE_EXTENSIONS.has(lastExtension)) {
|
|
92
|
+
const nameWithoutLastExt = fileName.substring(0, lastDotIndex);
|
|
93
|
+
const innerExtension = getFullFileExtension(nameWithoutLastExt, depth + 1);
|
|
94
|
+
if (innerExtension) {
|
|
95
|
+
// Concatena l'estensione interna con quella corrente
|
|
96
|
+
return innerExtension + fileName.substring(lastDotIndex);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Estensione singola (o estensione base dopo le firme)
|
|
100
|
+
return fileName.substring(lastDotIndex);
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Estrae il nome base del file (senza estensione completa).
|
|
104
|
+
* Gestisce estensioni composite come .PDF.P7M
|
|
105
|
+
*/
|
|
106
|
+
export const getFileBaseName = (fileName) => {
|
|
107
|
+
if (!fileName)
|
|
108
|
+
return '';
|
|
109
|
+
const fullExtension = getFullFileExtension(fileName);
|
|
110
|
+
if (!fullExtension)
|
|
111
|
+
return fileName;
|
|
112
|
+
return fileName.substring(0, fileName.length - fullExtension.length);
|
|
113
|
+
};
|
|
114
|
+
// ============================================================
|
|
115
|
+
// Sanitizzazione e gestione nomi file
|
|
116
|
+
// ============================================================
|
|
117
|
+
/** Sanitizza il nome file per Windows (rimuove caratteri illegali e limita la lunghezza) */
|
|
118
|
+
export const sanitizeFileName = (fileName, fallbackName, maxLength = 255) => {
|
|
119
|
+
try {
|
|
120
|
+
const illegalCharsRegex = /[<>:"/\\|?*]/g;
|
|
121
|
+
const controlCharsRegex = /[\x00-\x1F\x7F]/g;
|
|
122
|
+
let sanitized = fileName
|
|
123
|
+
.replace(illegalCharsRegex, '_')
|
|
124
|
+
.replace(controlCharsRegex, '')
|
|
125
|
+
.trim();
|
|
126
|
+
sanitized = sanitized.replace(/[. ]+$/, '');
|
|
127
|
+
if (sanitized.length > maxLength) {
|
|
128
|
+
const extension = getFullFileExtension(sanitized);
|
|
129
|
+
if (extension) {
|
|
130
|
+
const baseName = getFileBaseName(sanitized);
|
|
131
|
+
const maxBaseLength = maxLength - extension.length;
|
|
132
|
+
sanitized = baseName.substring(0, maxBaseLength) + extension;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
sanitized = sanitized.substring(0, maxLength);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return sanitized || fallbackName;
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return fallbackName;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
/** Verifica se un file esiste nella cartella (FileSystemDirectoryHandle) */
|
|
145
|
+
export const fileExists = async (dirHandle, fileName) => {
|
|
146
|
+
try {
|
|
147
|
+
await dirHandle.getFileHandle(fileName, { create: false });
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
/** Genera un nome file univoco aggiungendo un suffisso numerico se già esistente */
|
|
155
|
+
export const generateUniqueFileName = async (dirHandle, originalName) => {
|
|
156
|
+
try {
|
|
157
|
+
const baseName = getFileBaseName(originalName);
|
|
158
|
+
const extension = getFullFileExtension(originalName);
|
|
159
|
+
const MAX_ATTEMPTS = 1000;
|
|
160
|
+
for (let counter = 1; counter <= MAX_ATTEMPTS; counter++) {
|
|
161
|
+
const candidateName = counter === 1 ? originalName : `${baseName} (${counter - 1})${extension}`;
|
|
162
|
+
try {
|
|
163
|
+
await dirHandle.getFileHandle(candidateName, { create: false });
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return candidateName;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return `${baseName}_${Date.now()}${extension}`;
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
const baseName = getFileBaseName(originalName);
|
|
173
|
+
const extension = getFullFileExtension(originalName);
|
|
174
|
+
return `${baseName}_${Date.now()}${extension}`;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
// ============================================================
|
|
178
|
+
// Helper per la generazione del nome di destinazione del file
|
|
179
|
+
// (in base alle impostazioni utente: tipo, metadati, separatore...)
|
|
180
|
+
// ============================================================
|
|
181
|
+
/** Recupera il nome leggibile del tipo documento (cache) */
|
|
182
|
+
export const getTypeName = async (tid) => {
|
|
183
|
+
const typeList = await DcmtTypeListCacheService.GetAllWithoutMetadataAsync();
|
|
184
|
+
const foundDtd = typeList.find(dtd => dtd.id?.toString() === tid?.toString());
|
|
185
|
+
return foundDtd?.name ?? String(tid);
|
|
186
|
+
};
|
|
187
|
+
/** Formatta un valore convertendo le date in formato dd-MM-yyyy [HH-mm-ss] */
|
|
188
|
+
export const formatMetadataValue = (value) => {
|
|
189
|
+
const date = new Date(value);
|
|
190
|
+
if (!isNaN(date.getTime())) {
|
|
191
|
+
const day = date.getDate().toString().padStart(2, '0');
|
|
192
|
+
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
193
|
+
const year = date.getFullYear();
|
|
194
|
+
const hours = date.getHours();
|
|
195
|
+
const minutes = date.getMinutes();
|
|
196
|
+
const seconds = date.getSeconds();
|
|
197
|
+
if (hours !== 0 || minutes !== 0 || seconds !== 0) {
|
|
198
|
+
const hh = hours.toString().padStart(2, '0');
|
|
199
|
+
const mm = minutes.toString().padStart(2, '0');
|
|
200
|
+
const ss = seconds.toString().padStart(2, '0');
|
|
201
|
+
return `${day}-${month}-${year} ${hh}-${mm}-${ss}`;
|
|
202
|
+
}
|
|
203
|
+
return `${day}-${month}-${year}`;
|
|
204
|
+
}
|
|
205
|
+
return value;
|
|
206
|
+
};
|
|
207
|
+
/** Recupera i metadati filtrati (primi 5 con mid > 100 e valore presente), concatenati con separatorChar */
|
|
208
|
+
export const getFilteredMetadata = async (tid, did, separatorChar) => {
|
|
209
|
+
const metadata = await SDK_Globals.tmSession?.NewSearchEngine().GetMetadataAsync(tid, did, true);
|
|
210
|
+
if (!metadata)
|
|
211
|
+
return null;
|
|
212
|
+
const dtdResult = metadata.dtdResult;
|
|
213
|
+
const rows = dtdResult?.rows?.[0] ?? [];
|
|
214
|
+
const mids = metadata.selectMIDs;
|
|
215
|
+
const dtdWithMetadata = await DcmtTypeListCacheService.GetWithNotGrantedAsync(tid, did, metadata);
|
|
216
|
+
const mdList = dtdWithMetadata?.metadata ?? [];
|
|
217
|
+
const metadataList = searchResultToMetadataValues(tid, dtdResult, rows, mids, mdList, LayoutModes.Update);
|
|
218
|
+
return metadataList
|
|
219
|
+
.reduce((acc, md) => acc.length < 5 && md.mid && md.mid > 100 && md.value ? [...acc, formatMetadataValue(md.value)] : acc, [])
|
|
220
|
+
.join(separatorChar);
|
|
221
|
+
};
|
|
222
|
+
/** Genera il nome file di destinazione in base alle impostazioni di naming */
|
|
223
|
+
export const generateTargetFileName = async (file, dcmtInfo, options) => {
|
|
224
|
+
const { fileNamingMode, separatorChar } = options;
|
|
225
|
+
// Usa getFullFileExtension per gestire estensioni composite come .PDF.P7M, .DOCX.p7m
|
|
226
|
+
const fileExtension = getFullFileExtension(file.name);
|
|
227
|
+
const fallbackName = dcmtInfo.DID + fileExtension;
|
|
228
|
+
let targetFileName = file.name;
|
|
229
|
+
switch (fileNamingMode) {
|
|
230
|
+
case 'onlyDid':
|
|
231
|
+
targetFileName = fallbackName;
|
|
232
|
+
break;
|
|
233
|
+
case 'documentTypeAndDid': {
|
|
234
|
+
const typeName = await getTypeName(dcmtInfo.TID);
|
|
235
|
+
targetFileName = `${typeName}${separatorChar}${dcmtInfo.DID}${fileExtension}`;
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
case 'documentTypeAndCustomMetadata':
|
|
239
|
+
case 'onlyCustomMetadata': {
|
|
240
|
+
try {
|
|
241
|
+
const filteredMetadata = await getFilteredMetadata(dcmtInfo.TID, dcmtInfo.DID, separatorChar);
|
|
242
|
+
if (filteredMetadata) {
|
|
243
|
+
if (fileNamingMode === 'documentTypeAndCustomMetadata') {
|
|
244
|
+
const typeName = await getTypeName(dcmtInfo.TID);
|
|
245
|
+
targetFileName = `${typeName}${separatorChar}${filteredMetadata}${fileExtension}`;
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
targetFileName = `${filteredMetadata}${fileExtension}`;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
targetFileName = fallbackName;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
targetFileName = fallbackName;
|
|
257
|
+
}
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
default:
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
return sanitizeFileName(targetFileName, fallbackName);
|
|
264
|
+
};
|
|
265
|
+
// ============================================================
|
|
266
|
+
// Build della lista di DcmtInfo effettivi da scaricare
|
|
267
|
+
// ============================================================
|
|
268
|
+
/**
|
|
269
|
+
* Restituisce i documenti da scaricare:
|
|
270
|
+
* - se è visibile il TMRelationViewer, usa gli isDcmt selezionati al suo interno
|
|
271
|
+
* - altrimenti restituisce i selectedDcmtInfos passati come prop
|
|
272
|
+
*/
|
|
273
|
+
export const getDcmtInfosToDownload = (selectedDcmtInfos, selectedItemsRelationViewer, showTMRelationViewer) => {
|
|
274
|
+
if (showTMRelationViewer) {
|
|
275
|
+
return selectedItemsRelationViewer
|
|
276
|
+
.filter(i => i.isDcmt && i.tid != null && i.did != null)
|
|
277
|
+
.map(i => ({ TID: i.tid, DID: i.did }));
|
|
278
|
+
}
|
|
279
|
+
return selectedDcmtInfos;
|
|
280
|
+
};
|
|
281
|
+
// ============================================================
|
|
282
|
+
// Stato iniziale settings (con valori salvati o default)
|
|
283
|
+
// ============================================================
|
|
284
|
+
/**
|
|
285
|
+
* Costruisce lo stato iniziale di DocumentDownloadSettings combinando:
|
|
286
|
+
* - i valori salvati in userSettings (se presenti)
|
|
287
|
+
* - i default della classe
|
|
288
|
+
* Nota: destinationFolder e zipPassword vengono sempre resettati per sicurezza.
|
|
289
|
+
*/
|
|
290
|
+
export const buildInitialDownloadSettings = (saved, defaultInvoiceFormat, defaultOrderFormat) => {
|
|
291
|
+
const defaults = new DocumentDownloadSettings();
|
|
292
|
+
return {
|
|
293
|
+
exportMode: saved?.exportMode ?? defaults.exportMode,
|
|
294
|
+
destinationFolder: 'Download',
|
|
295
|
+
zipFileName: saved?.zipFileName ?? defaults.zipFileName,
|
|
296
|
+
zipPassword: '',
|
|
297
|
+
fileNamingMode: saved?.fileNamingMode ?? defaults.fileNamingMode,
|
|
298
|
+
separatorChar: saved?.separatorChar ?? defaults.separatorChar,
|
|
299
|
+
invoiceFormat: saved?.invoiceFormat ?? defaultInvoiceFormat,
|
|
300
|
+
orderFormat: saved?.orderFormat ?? defaultOrderFormat,
|
|
301
|
+
fileExistsMode: saved?.fileExistsMode ?? defaults.fileExistsMode,
|
|
302
|
+
removeSignature: saved?.removeSignature ?? defaults.removeSignature,
|
|
303
|
+
};
|
|
304
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export declare const DEFAULT_SIGNATURE_TID = -1;
|
|
2
|
+
export type SignatureMethodCode = 'T' | 'D' | 'U';
|
|
3
|
+
export interface SignatureEntry {
|
|
4
|
+
/** TID del tipo documento associato alla firma (-1 = firma di default globale) */
|
|
5
|
+
tid: number;
|
|
6
|
+
/** Immagine della firma in formato base64 (data URL) */
|
|
7
|
+
imgSign: string;
|
|
8
|
+
/** Metodo utilizzato: 'T' = Testo, 'D' = Disegno, 'U' = Upload */
|
|
9
|
+
method: SignatureMethodCode;
|
|
10
|
+
/** Testo utilizzato per generare la firma (solo per method='T') */
|
|
11
|
+
signText?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface SignatureResult {
|
|
14
|
+
/** Immagine della firma in formato base64 (data URL) */
|
|
15
|
+
imgSign: string;
|
|
16
|
+
/** true se è stata usata la firma di default (tid = -1) */
|
|
17
|
+
isDefault: boolean;
|
|
18
|
+
/** TID effettivo della firma trovata */
|
|
19
|
+
sourceTid: number;
|
|
20
|
+
/** Metodo utilizzato: 'T' = Testo, 'D' = Disegno, 'U' = Upload */
|
|
21
|
+
method: SignatureMethodCode;
|
|
22
|
+
/** Testo utilizzato per generare la firma (solo per method='T') */
|
|
23
|
+
signText?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Classe helper per gestire le firme predefinite salvate come JSON array.
|
|
27
|
+
* Centralizza tutte le operazioni di lettura/scrittura/eliminazione.
|
|
28
|
+
*/
|
|
29
|
+
export declare class SignatureParamsManager {
|
|
30
|
+
private static cache;
|
|
31
|
+
/**
|
|
32
|
+
* Svuota la cache locale. Utile per forzare un refresh dei dati.
|
|
33
|
+
*/
|
|
34
|
+
static clearCache(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Recupera tutte le firme salvate (usa cache locale se disponibile)
|
|
37
|
+
*/
|
|
38
|
+
static getAll(): Promise<SignatureEntry[]>;
|
|
39
|
+
/**
|
|
40
|
+
* Recupera la firma per un TID specifico (senza fallback).
|
|
41
|
+
* Restituisce solo la firma associata al TID richiesto, o undefined se non esiste.
|
|
42
|
+
*/
|
|
43
|
+
static getByTid(tid: number): Promise<SignatureResult | undefined>;
|
|
44
|
+
/**
|
|
45
|
+
* Recupera la firma per un TID specifico con fallback alla firma di default.
|
|
46
|
+
* Se non trova la firma per il TID specifico, prova con la firma di default (tid = -1).
|
|
47
|
+
* Se non esiste neanche quella, restituisce undefined.
|
|
48
|
+
* Restituisce anche l'informazione se è stata usata la firma di default.
|
|
49
|
+
*/
|
|
50
|
+
static getByTidWithFallback(tid: number): Promise<SignatureResult | undefined>;
|
|
51
|
+
/**
|
|
52
|
+
* Salva la firma di default valida per tutti i tipi documento (tid = 0)
|
|
53
|
+
* @param imgSign Immagine firma in base64
|
|
54
|
+
* @param method Metodo utilizzato per creare la firma
|
|
55
|
+
* @param signText Testo utilizzato per generare la firma (solo per method='T')
|
|
56
|
+
*/
|
|
57
|
+
static saveDefault(imgSign: string, method: SignatureMethodCode, signText?: string): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Salva o aggiorna la firma per un TID specifico
|
|
60
|
+
* @param tid ID del tipo documento
|
|
61
|
+
* @param imgSign Immagine firma in base64
|
|
62
|
+
* @param method Metodo utilizzato per creare la firma
|
|
63
|
+
* @param signText Testo utilizzato per generare la firma (solo per method='T')
|
|
64
|
+
*/
|
|
65
|
+
static save(tid: number, imgSign: string, method: SignatureMethodCode, signText?: string): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Elimina la firma per un TID specifico
|
|
68
|
+
*/
|
|
69
|
+
static delete(tid: number): Promise<void>;
|
|
70
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { SDK_Globals } from "@topconsultnpm/sdk-ts";
|
|
2
|
+
const SIGNATURE_PARAM_KEY = 'signParams'; // Chiave unica parametro per tutte le firme predefinite (JSON array)
|
|
3
|
+
export const DEFAULT_SIGNATURE_TID = -1; // TID speciale per firma di default valida per tutti i tipi documento
|
|
4
|
+
/**
|
|
5
|
+
* Classe helper per gestire le firme predefinite salvate come JSON array.
|
|
6
|
+
* Centralizza tutte le operazioni di lettura/scrittura/eliminazione.
|
|
7
|
+
*/
|
|
8
|
+
export class SignatureParamsManager {
|
|
9
|
+
/**
|
|
10
|
+
* Svuota la cache locale. Utile per forzare un refresh dei dati.
|
|
11
|
+
*/
|
|
12
|
+
static clearCache() {
|
|
13
|
+
this.cache = null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Recupera tutte le firme salvate (usa cache locale se disponibile)
|
|
17
|
+
*/
|
|
18
|
+
static async getAll() {
|
|
19
|
+
// Se la cache è valorizzata, restituisci direttamente
|
|
20
|
+
if (this.cache !== null) {
|
|
21
|
+
return this.cache;
|
|
22
|
+
}
|
|
23
|
+
const jsonValue = await SDK_Globals.tmSession?.NewUserEngine().ParamGetAsync(SIGNATURE_PARAM_KEY);
|
|
24
|
+
if (!jsonValue || jsonValue === '') {
|
|
25
|
+
this.cache = [];
|
|
26
|
+
return this.cache;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
this.cache = JSON.parse(jsonValue);
|
|
30
|
+
return this.cache;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
console.warn('Errore parsing JSON firme, formato non valido');
|
|
34
|
+
this.cache = [];
|
|
35
|
+
return this.cache;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Recupera la firma per un TID specifico (senza fallback).
|
|
40
|
+
* Restituisce solo la firma associata al TID richiesto, o undefined se non esiste.
|
|
41
|
+
*/
|
|
42
|
+
static async getByTid(tid) {
|
|
43
|
+
const signatures = await this.getAll();
|
|
44
|
+
const entry = signatures.find(s => s.tid.toString() === tid.toString());
|
|
45
|
+
if (entry?.imgSign) {
|
|
46
|
+
return {
|
|
47
|
+
imgSign: entry.imgSign,
|
|
48
|
+
isDefault: tid.toString() === DEFAULT_SIGNATURE_TID.toString(),
|
|
49
|
+
sourceTid: tid,
|
|
50
|
+
method: entry.method,
|
|
51
|
+
signText: entry.signText
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Recupera la firma per un TID specifico con fallback alla firma di default.
|
|
58
|
+
* Se non trova la firma per il TID specifico, prova con la firma di default (tid = -1).
|
|
59
|
+
* Se non esiste neanche quella, restituisce undefined.
|
|
60
|
+
* Restituisce anche l'informazione se è stata usata la firma di default.
|
|
61
|
+
*/
|
|
62
|
+
static async getByTidWithFallback(tid) {
|
|
63
|
+
// Prima cerca la firma per il TID specifico
|
|
64
|
+
const specificResult = await this.getByTid(tid);
|
|
65
|
+
if (specificResult) {
|
|
66
|
+
return specificResult;
|
|
67
|
+
}
|
|
68
|
+
// Se non trova e il tid richiesto non è già il default, cerca la firma di default (tid = -1)
|
|
69
|
+
if (tid.toString() !== DEFAULT_SIGNATURE_TID.toString()) {
|
|
70
|
+
const defaultResult = await this.getByTid(DEFAULT_SIGNATURE_TID);
|
|
71
|
+
if (defaultResult) {
|
|
72
|
+
return {
|
|
73
|
+
...defaultResult,
|
|
74
|
+
isDefault: true
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Salva la firma di default valida per tutti i tipi documento (tid = 0)
|
|
82
|
+
* @param imgSign Immagine firma in base64
|
|
83
|
+
* @param method Metodo utilizzato per creare la firma
|
|
84
|
+
* @param signText Testo utilizzato per generare la firma (solo per method='T')
|
|
85
|
+
*/
|
|
86
|
+
static async saveDefault(imgSign, method, signText) {
|
|
87
|
+
await this.save(DEFAULT_SIGNATURE_TID, imgSign, method, signText);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Salva o aggiorna la firma per un TID specifico
|
|
91
|
+
* @param tid ID del tipo documento
|
|
92
|
+
* @param imgSign Immagine firma in base64
|
|
93
|
+
* @param method Metodo utilizzato per creare la firma
|
|
94
|
+
* @param signText Testo utilizzato per generare la firma (solo per method='T')
|
|
95
|
+
*/
|
|
96
|
+
static async save(tid, imgSign, method, signText) {
|
|
97
|
+
const signatures = await this.getAll();
|
|
98
|
+
const existingIndex = signatures.findIndex(s => s.tid.toString() === tid.toString());
|
|
99
|
+
// Il testo della firma (signText) viene salvato SOLO quando:
|
|
100
|
+
// 1. Il metodo di creazione è 'T' (TextEditor)
|
|
101
|
+
// 2. Il testo esiste ed è valorizzato
|
|
102
|
+
// Per i metodi 'D' (Disegno) e 'U' (Upload) il campo signText non viene mai salvato
|
|
103
|
+
const shouldSaveText = method === 'T' && signText;
|
|
104
|
+
// Pattern UPSERT: aggiorna se esiste, altrimenti crea nuova entry
|
|
105
|
+
if (existingIndex >= 0) {
|
|
106
|
+
// Aggiorna una firma esistente
|
|
107
|
+
signatures[existingIndex].imgSign = imgSign;
|
|
108
|
+
signatures[existingIndex].method = method;
|
|
109
|
+
if (shouldSaveText) {
|
|
110
|
+
// Salva il testo solo per metodo 'T' con testo valorizzato
|
|
111
|
+
signatures[existingIndex].signText = signText;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
// Rimuove signText se presente (es. cambio da 'T' a 'D' o 'U')
|
|
115
|
+
delete signatures[existingIndex].signText;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
// Crea una nuova entry senza includere signText di default
|
|
120
|
+
const entry = { tid, imgSign, method };
|
|
121
|
+
if (shouldSaveText) {
|
|
122
|
+
// Aggiunge signText solo se necessario
|
|
123
|
+
entry.signText = signText;
|
|
124
|
+
}
|
|
125
|
+
signatures.push(entry);
|
|
126
|
+
}
|
|
127
|
+
await SDK_Globals.tmSession?.NewUserEngine().ParamSetAsync(SIGNATURE_PARAM_KEY, JSON.stringify(signatures));
|
|
128
|
+
// Aggiorna la cache dopo il salvataggio
|
|
129
|
+
this.clearCache();
|
|
130
|
+
await this.getAll();
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Elimina la firma per un TID specifico
|
|
134
|
+
*/
|
|
135
|
+
static async delete(tid) {
|
|
136
|
+
const signatures = await this.getAll();
|
|
137
|
+
const filtered = signatures.filter(s => s.tid.toString() !== tid.toString());
|
|
138
|
+
await SDK_Globals.tmSession?.NewUserEngine().ParamSetAsync(SIGNATURE_PARAM_KEY, JSON.stringify(filtered));
|
|
139
|
+
// Aggiorna la cache dopo l'eliminazione
|
|
140
|
+
this.clearCache();
|
|
141
|
+
await this.getAll();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Cache locale per evitare chiamate ripetute
|
|
145
|
+
SignatureParamsManager.cache = null;
|
|
@@ -9,8 +9,8 @@ interface ITMSavedQuerySelectorProps {
|
|
|
9
9
|
manageDefault?: boolean;
|
|
10
10
|
onItemClick?: (sqd: SavedQueryDescriptor) => void;
|
|
11
11
|
onDeleted?: (sqd: SavedQueryDescriptor) => void;
|
|
12
|
-
|
|
12
|
+
refreshFavoriteSavedQueries?: (sqd: SavedQueryDescriptor) => void;
|
|
13
13
|
onRefreshData?: () => void;
|
|
14
14
|
}
|
|
15
|
-
declare const TMSavedQuerySelector: React.MemoExoticComponent<({ items, selectedId, allowShowSearch, height, manageDefault, onItemClick, onDeleted,
|
|
15
|
+
declare const TMSavedQuerySelector: React.MemoExoticComponent<({ items, selectedId, allowShowSearch, height, manageDefault, onItemClick, onDeleted, refreshFavoriteSavedQueries, onRefreshData }: ITMSavedQuerySelectorProps) => import("react/jsx-runtime").JSX.Element>;
|
|
16
16
|
export default TMSavedQuerySelector;
|
|
@@ -105,7 +105,7 @@ const getContextMenuItems = (sqd, manageDefault, isMobile, deleteAsync, setDefau
|
|
|
105
105
|
onClick: () => { setInfoSQD?.(sqd); }
|
|
106
106
|
}] : [])
|
|
107
107
|
];
|
|
108
|
-
const TMSavedQuerySelector = React.memo(({ items, selectedId, allowShowSearch = true, height, manageDefault = true, onItemClick, onDeleted,
|
|
108
|
+
const TMSavedQuerySelector = React.memo(({ items, selectedId, allowShowSearch = true, height, manageDefault = true, onItemClick, onDeleted, refreshFavoriteSavedQueries, onRefreshData }) => {
|
|
109
109
|
const [dataSource, setDataSource] = useState([]);
|
|
110
110
|
const [selectedItem, setSelectedItem] = useState();
|
|
111
111
|
const [searchText, setSearchText] = useState('');
|
|
@@ -135,6 +135,7 @@ const TMSavedQuerySelector = React.memo(({ items, selectedId, allowShowSearch =
|
|
|
135
135
|
await SDK_Globals.tmSession?.NewSavedQueryEngine().DeleteAsync(sqd?.id);
|
|
136
136
|
await loadDataAsync(true);
|
|
137
137
|
onDeleted?.(sqd);
|
|
138
|
+
refreshFavoriteSavedQueries?.(sqd);
|
|
138
139
|
TMSpinner.hide();
|
|
139
140
|
}
|
|
140
141
|
catch (ex) {
|
|
@@ -148,7 +149,7 @@ const TMSavedQuerySelector = React.memo(({ items, selectedId, allowShowSearch =
|
|
|
148
149
|
try {
|
|
149
150
|
TMSpinner.show();
|
|
150
151
|
await SDK_Globals.tmSession?.NewSavedQueryEngine().FavoritesAddOrRemoveAsync(sqd?.id, false);
|
|
151
|
-
|
|
152
|
+
refreshFavoriteSavedQueries?.(sqd);
|
|
152
153
|
TMSpinner.hide();
|
|
153
154
|
ShowAlert({ mode: 'success', title: SDK_Localizator.SavedQuery, message: SDKUI_Localizator.OperationSuccess, duration: 3000 });
|
|
154
155
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { DcmtTypeDescriptor, TaskDescriptor, ObjectRef, HomeBlogPost } from '@topconsultnpm/sdk-ts';
|
|
2
|
+
import { SavedQueryDescriptor, DcmtTypeDescriptor, TaskDescriptor, ObjectRef, HomeBlogPost } from '@topconsultnpm/sdk-ts';
|
|
3
|
+
import { MergePdfManagerType } from '../../../helper';
|
|
3
4
|
import { DcmtInfo, TaskContext } from '../../../ts';
|
|
4
5
|
import { TMSearchResultFloatingActionConfig } from './TMSearchResultFloatingActionButton';
|
|
5
6
|
interface ITMSearchProps {
|
|
@@ -36,9 +37,13 @@ interface ITMSearchProps {
|
|
|
36
37
|
mid: number;
|
|
37
38
|
value: string;
|
|
38
39
|
}>, tid?: number) => void;
|
|
40
|
+
refreshFavoriteSavedQueries?: (sqd: SavedQueryDescriptor) => void;
|
|
39
41
|
onCurrentTIDChangedCallback?: (tid: number | undefined) => void;
|
|
40
42
|
onlyShowSearchQueryPanel?: boolean;
|
|
41
43
|
onReferenceClick?: (ref: ObjectRef) => void;
|
|
44
|
+
inputDID?: number;
|
|
45
|
+
formAutoOpen?: boolean;
|
|
46
|
+
mergePdfManager?: MergePdfManagerType;
|
|
42
47
|
}
|
|
43
48
|
declare const TMSearch: React.FunctionComponent<ITMSearchProps>;
|
|
44
49
|
export default TMSearch;
|