@topconsultnpm/sdkui-react 6.21.0-dev2.4 → 6.21.0-dev2.41

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 (80) hide show
  1. package/lib/components/base/TMAccordionNew.js +1 -0
  2. package/lib/components/base/TMAreaManager.js +19 -3
  3. package/lib/components/base/TMDataGrid.js +2 -2
  4. package/lib/components/base/TMPanel.d.ts +7 -4
  5. package/lib/components/base/TMPanel.js +58 -26
  6. package/lib/components/choosers/TMDistinctValues.js +35 -21
  7. package/lib/components/choosers/TMUserChooser.d.ts +4 -0
  8. package/lib/components/choosers/TMUserChooser.js +7 -5
  9. package/lib/components/editors/TMDateBox.js +4 -2
  10. package/lib/components/editors/TMFormulaEditor.d.ts +2 -0
  11. package/lib/components/editors/TMFormulaEditor.js +75 -21
  12. package/lib/components/editors/TMMetadataValues.js +2 -1
  13. package/lib/components/editors/TMRadioButton.js +2 -1
  14. package/lib/components/editors/TMTextArea.d.ts +2 -0
  15. package/lib/components/editors/TMTextArea.js +6 -3
  16. package/lib/components/editors/TMTextBox.d.ts +2 -0
  17. package/lib/components/editors/TMTextBox.js +3 -3
  18. package/lib/components/features/archive/TMArchive.js +1 -1
  19. package/lib/components/features/documents/TMCopyToFolderForm.d.ts +24 -0
  20. package/lib/components/features/documents/TMCopyToFolderForm.js +346 -0
  21. package/lib/components/features/documents/TMDcmtForm.d.ts +1 -0
  22. package/lib/components/features/documents/TMDcmtForm.js +107 -29
  23. package/lib/components/features/documents/TMDcmtFormActionButtons.js +17 -2
  24. package/lib/components/features/documents/TMDcmtPreview.d.ts +1 -0
  25. package/lib/components/features/documents/TMDcmtPreview.js +2 -2
  26. package/lib/components/features/documents/TMDcmtTasks.d.ts +1 -0
  27. package/lib/components/features/documents/TMDcmtTasks.js +2 -2
  28. package/lib/components/features/documents/TMDownloadRelationViewerSection.d.ts +23 -0
  29. package/lib/components/features/documents/TMDownloadRelationViewerSection.js +173 -0
  30. package/lib/components/features/documents/TMFileUploader.js +1 -1
  31. package/lib/components/features/documents/TMMasterDetailDcmts.d.ts +4 -0
  32. package/lib/components/features/documents/TMMasterDetailDcmts.js +6 -5
  33. package/lib/components/features/documents/TMMergeToPdfForm.d.ts +26 -0
  34. package/lib/components/features/documents/TMMergeToPdfForm.js +276 -0
  35. package/lib/components/features/documents/TMRelationViewer.d.ts +13 -0
  36. package/lib/components/features/documents/TMRelationViewer.js +75 -6
  37. package/lib/components/features/documents/copyAndMergeDcmtsShared.d.ts +54 -0
  38. package/lib/components/features/documents/copyAndMergeDcmtsShared.js +263 -0
  39. package/lib/components/features/search/SignatureParamsManager.d.ts +70 -0
  40. package/lib/components/features/search/SignatureParamsManager.js +145 -0
  41. package/lib/components/features/search/TMSavedQuerySelector.d.ts +2 -2
  42. package/lib/components/features/search/TMSavedQuerySelector.js +3 -2
  43. package/lib/components/features/search/TMSearch.d.ts +6 -1
  44. package/lib/components/features/search/TMSearch.js +16 -10
  45. package/lib/components/features/search/TMSearchQueryPanel.js +1 -1
  46. package/lib/components/features/search/TMSearchResult.d.ts +4 -0
  47. package/lib/components/features/search/TMSearchResult.js +86 -21
  48. package/lib/components/features/search/TMViewHistoryDcmt.js +1 -2
  49. package/lib/components/features/workflow/diagram/queryDescriptorParser.js +3 -6
  50. package/lib/components/forms/Login/TMLoginForm.d.ts +9 -0
  51. package/lib/components/forms/Login/TMLoginForm.js +44 -0
  52. package/lib/components/grids/TMBlogAttachments.d.ts +1 -0
  53. package/lib/components/grids/TMBlogAttachments.js +38 -12
  54. package/lib/components/grids/TMBlogsPost.js +7 -1
  55. package/lib/components/grids/TMBlogsPostUtils.js +11 -17
  56. package/lib/components/index.d.ts +1 -0
  57. package/lib/components/index.js +1 -0
  58. package/lib/components/pages/TMPage.js +3 -1
  59. package/lib/components/query/TMQueryEditor.js +1 -1
  60. package/lib/components/viewers/TMTidViewer.js +1 -1
  61. package/lib/helper/GlobalStyles.js +6 -0
  62. package/lib/helper/SDKUI_Globals.d.ts +15 -0
  63. package/lib/helper/SDKUI_Globals.js +15 -1
  64. package/lib/helper/SDKUI_Localizator.d.ts +52 -0
  65. package/lib/helper/SDKUI_Localizator.js +522 -0
  66. package/lib/helper/TMPdfViewer.js +25 -24
  67. package/lib/helper/TMUtils.d.ts +19 -0
  68. package/lib/helper/ZipManager.d.ts +56 -0
  69. package/lib/helper/ZipManager.js +104 -0
  70. package/lib/helper/index.d.ts +1 -0
  71. package/lib/helper/index.js +1 -0
  72. package/lib/hooks/useDataUserIdItem.js +6 -4
  73. package/lib/hooks/useDcmtOperations.d.ts +9 -2
  74. package/lib/hooks/useDcmtOperations.js +31 -20
  75. package/lib/hooks/useDocumentOperations.d.ts +5 -0
  76. package/lib/hooks/useDocumentOperations.js +90 -20
  77. package/lib/hooks/useForm.js +5 -2
  78. package/lib/hooks/useResizeObserver.d.ts +1 -1
  79. package/lib/hooks/useResizeObserver.js +16 -15
  80. package/package.json +3 -2
@@ -0,0 +1,346 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRef, useState } from 'react';
3
+ import { DownloadTypes } from '../../../ts';
4
+ import { calcResponsiveSizes, DocumentDownloadSettings, IconDelete, IconFolderOpen, IconPlay, IconSave, IconUndo, SDKUI_Globals, SDKUI_Localizator, ZipManager, } from '../../../helper';
5
+ import { DcmtOpers, GeneralRetrieveFormats, ResultTypes, RetrieveFileOptions, ValidationItem, } from '@topconsultnpm/sdk-ts';
6
+ import TMModal from '../../base/TMModal';
7
+ import { useDeviceType } from '../../base/TMDeviceProvider';
8
+ import TMRadioButton from '../../editors/TMRadioButton';
9
+ import TMTextBox from '../../editors/TMTextBox';
10
+ import TMDropDown from '../../editors/TMDropDown';
11
+ import TMInvoiceRetrieveFormats from '../../choosers/TMInvoiceRetrieveFormats';
12
+ import TMOrderRetrieveFormats from '../../choosers/TMOrderRetrieveFormats';
13
+ import TMButton from '../../base/TMButton';
14
+ import { ButtonNames, TMMessageBoxManager } from '../../base/TMPopUp';
15
+ import { useDcmtOperations } from '../../../hooks/useDcmtOperations';
16
+ import { TMLayoutWaitingContainer } from '../../base/TMWaitPanel';
17
+ import { TMSplitterLayout } from '../../base/TMLayout';
18
+ import TMCheckBox from '../../editors/TMCheckBox';
19
+ import ShowAlert from '../../base/TMAlert';
20
+ import { TMColors } from '../../../utils/theme';
21
+ import TMDownloadRelationViewerSection from './TMDownloadRelationViewerSection';
22
+ import { buildInitialDownloadSettings, fileExists, generateTargetFileName, generateUniqueFileName, getDcmtInfosToDownload, getFloatingLabelStyle, isDirectoryPickerSupported, SPLITTER_MIN, SPLITTER_START_60_40, } from './copyAndMergeDcmtsShared';
23
+ /**
24
+ * Form per la copia/zip dei documenti in una cartella locale.
25
+ * Logica condivisa con TMMergeToPdfForm è esternalizzata in copyAndMergeDcmtsShared
26
+ * e TMDownloadRelationViewerSection.
27
+ */
28
+ const TMCopyToFolderForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationViewer, allTasks, getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers }) => {
29
+ const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, } = useDcmtOperations();
30
+ const deviceType = useDeviceType();
31
+ // ---- Stato dei settings ----
32
+ const [settings, setSettings] = useState(() => buildInitialDownloadSettings(SDKUI_Globals.userSettings.documentDownloadSettings, SDKUI_Globals.userSettings.searchSettings.invoiceRetrieveFormat, SDKUI_Globals.userSettings.searchSettings.orderRetrieveFormat));
33
+ const [selectedItemsRelationViewer, setSelectedItemsRelationViewer] = useState([]);
34
+ const [hasSavedLayout, setHasSavedLayout] = useState(() => {
35
+ const saved = SDKUI_Globals.userSettings.documentDownloadSettings;
36
+ const defaults = new DocumentDownloadSettings();
37
+ return JSON.stringify(saved) !== JSON.stringify(defaults);
38
+ });
39
+ const updateSettings = (key, value) => {
40
+ setSettings(prev => ({ ...prev, [key]: value }));
41
+ };
42
+ // ---- Ref per la selezione cartella (File System Access API) ----
43
+ const folderHandleRef = useRef(null);
44
+ const skipSelectFolderRef = useRef(false);
45
+ const isPickerActiveRef = useRef(false);
46
+ const getTitle = () => {
47
+ const count = ` (${selectedDcmtInfos.length})`;
48
+ const modeLabelMap = {
49
+ onlySelected: 'I documenti selezionati',
50
+ customized: 'I documenti selezionati e i correlati',
51
+ };
52
+ const modeLabel = modeLabelMap[mode] || modeLabelMap.onlySelected;
53
+ return `Copia in una cartella - ${modeLabel}${count}`;
54
+ };
55
+ const isUsingDefaultDownloads = settings.destinationFolder === 'Download' && !folderHandleRef.current;
56
+ // ---- Validazione ----
57
+ const folderValidationItems = [];
58
+ if (settings.exportMode === 'copy' && !settings.destinationFolder.trim()) {
59
+ folderValidationItems.push(new ValidationItem(ResultTypes.ERROR, 'Cartella di destinazione', SDKUI_Localizator.RequiredField));
60
+ }
61
+ const zipValidationItems = [];
62
+ if (settings.exportMode === 'zip' && !settings.zipFileName.trim()) {
63
+ zipValidationItems.push(new ValidationItem(ResultTypes.ERROR, 'Nome file zip', SDKUI_Localizator.RequiredField));
64
+ }
65
+ const isFormValid = () => {
66
+ if (settings.exportMode === 'copy')
67
+ return folderValidationItems.length === 0;
68
+ if (settings.exportMode === 'zip')
69
+ return zipValidationItems.length === 0;
70
+ return false;
71
+ };
72
+ // ---- Handler dei campi ----
73
+ const handleFolderValueChange = (e) => {
74
+ updateSettings('destinationFolder', e.target.value);
75
+ folderHandleRef.current = null;
76
+ };
77
+ const handleSelectFolder = async () => {
78
+ if (skipSelectFolderRef.current) {
79
+ skipSelectFolderRef.current = false;
80
+ return;
81
+ }
82
+ if (isPickerActiveRef.current)
83
+ return;
84
+ try {
85
+ isPickerActiveRef.current = true;
86
+ const dirHandle = await window.showDirectoryPicker({ mode: 'readwrite' });
87
+ folderHandleRef.current = dirHandle;
88
+ updateSettings('destinationFolder', dirHandle.name);
89
+ }
90
+ catch (err) {
91
+ if (err.name !== 'AbortError') {
92
+ console.error('Errore nella selezione della cartella:', err);
93
+ }
94
+ }
95
+ finally {
96
+ isPickerActiveRef.current = false;
97
+ }
98
+ };
99
+ const handleFileNamingModeChange = (e) => {
100
+ updateSettings('fileNamingMode', e.target.value);
101
+ };
102
+ const handleSeparatorChange = (e) => {
103
+ updateSettings('separatorChar', e.target.value.slice(0, 1));
104
+ };
105
+ // ---- Scrittura file nel filesystem locale ----
106
+ const writeFileToFolder = async (file, dcmtInfo) => {
107
+ try {
108
+ let targetFileName = await generateTargetFileName(file, dcmtInfo, {
109
+ fileNamingMode: settings.fileNamingMode,
110
+ separatorChar: settings.separatorChar,
111
+ });
112
+ // Se non c'è un handle della cartella: download standard del browser
113
+ if (!folderHandleRef.current) {
114
+ const url = URL.createObjectURL(file);
115
+ const a = document.createElement('a');
116
+ a.href = url;
117
+ a.download = targetFileName;
118
+ document.body.appendChild(a);
119
+ a.target = '_blank';
120
+ a.rel = 'noreferrer';
121
+ a.click();
122
+ document.body.removeChild(a);
123
+ URL.revokeObjectURL(url);
124
+ return;
125
+ }
126
+ const exists = await fileExists(folderHandleRef.current, targetFileName);
127
+ if (exists) {
128
+ switch (settings.fileExistsMode) {
129
+ case 'skip':
130
+ return;
131
+ case 'rename':
132
+ targetFileName = await generateUniqueFileName(folderHandleRef.current, targetFileName);
133
+ break;
134
+ case 'overwrite':
135
+ default:
136
+ break;
137
+ }
138
+ }
139
+ const fileHandle = await folderHandleRef.current.getFileHandle(targetFileName, { create: true });
140
+ const writable = await fileHandle.createWritable();
141
+ await writable.write(file);
142
+ await writable.close();
143
+ }
144
+ catch (err) {
145
+ console.error('Errore nella scrittura del file:', err);
146
+ throw err;
147
+ }
148
+ };
149
+ // ---- Esecuzione (Copia oppure ZIP) ----
150
+ const run = async () => {
151
+ if (settings.exportMode === 'copy' && folderValidationItems.length > 0) {
152
+ TMMessageBoxManager.show({ message: 'Per favore, correggi gli errori prima di procedere.', buttons: [ButtonNames.OK] });
153
+ return;
154
+ }
155
+ if (settings.exportMode === 'zip' && zipValidationItems.length > 0) {
156
+ TMMessageBoxManager.show({ message: 'Per favore, correggi gli errori prima di procedere.', buttons: [ButtonNames.OK] });
157
+ return;
158
+ }
159
+ const dcmtInfosToDownload = getDcmtInfosToDownload(selectedDcmtInfos, selectedItemsRelationViewer, showTMRelationViewer);
160
+ if (dcmtInfosToDownload.length === 0) {
161
+ TMMessageBoxManager.show({ message: 'Nessun documento selezionato.', buttons: [ButtonNames.OK] });
162
+ return;
163
+ }
164
+ const retrieveOptions = new RetrieveFileOptions();
165
+ retrieveOptions.retrieveReason = DcmtOpers.None;
166
+ retrieveOptions.generalRetrieveFormat = settings.removeSignature ? GeneralRetrieveFormats.OriginalUnsigned : GeneralRetrieveFormats.Original;
167
+ retrieveOptions.invoiceRetrieveFormat = settings.invoiceFormat ?? SDKUI_Globals.userSettings.searchSettings.invoiceRetrieveFormat;
168
+ retrieveOptions.orderRetrieveFormat = settings.orderFormat ?? SDKUI_Globals.userSettings.searchSettings.orderRetrieveFormat;
169
+ if (settings.exportMode === 'copy') {
170
+ await downloadDcmtsAsync(dcmtInfosToDownload, DownloadTypes.Dcmt, 'download', writeFileToFolder, undefined, true, retrieveOptions, false);
171
+ }
172
+ else if (settings.exportMode === 'zip') {
173
+ const zipEntries = [];
174
+ const fileNameCounts = new Map();
175
+ const getUniqueZipFileName = (fileName) => {
176
+ const lowerName = fileName.toLowerCase();
177
+ const count = fileNameCounts.get(lowerName) ?? 0;
178
+ fileNameCounts.set(lowerName, count + 1);
179
+ if (count === 0)
180
+ return fileName;
181
+ const dotIndex = fileName.lastIndexOf('.');
182
+ const baseName = dotIndex > 0 ? fileName.substring(0, dotIndex) : fileName;
183
+ const ext = dotIndex > 0 ? fileName.substring(dotIndex) : '';
184
+ return `${baseName} (${count})${ext}`;
185
+ };
186
+ const collectFileForZip = async (file, dcmtInfo) => {
187
+ const targetFileName = await generateTargetFileName(file, dcmtInfo, {
188
+ fileNamingMode: settings.fileNamingMode,
189
+ separatorChar: settings.separatorChar,
190
+ });
191
+ zipEntries.push({ filename: getUniqueZipFileName(targetFileName), data: file });
192
+ };
193
+ await downloadDcmtsAsync(dcmtInfosToDownload, DownloadTypes.Dcmt, 'download', collectFileForZip, undefined, true, retrieveOptions, false);
194
+ if (zipEntries.length > 0) {
195
+ const zipFileName = settings.zipFileName.trim().toLowerCase().endsWith('.zip')
196
+ ? settings.zipFileName.trim()
197
+ : settings.zipFileName.trim() + '.zip';
198
+ // Crea il blob ZIP
199
+ const zipBlob = await ZipManager.createZip(zipEntries, {
200
+ compressionLevel: 6,
201
+ password: settings.zipPassword.trim() || undefined,
202
+ });
203
+ // Se c'è un handle della cartella: salva direttamente nella cartella selezionata
204
+ if (folderHandleRef.current) {
205
+ try {
206
+ // Per lo ZIP usa sempre rename automatico (come fa il browser)
207
+ const finalZipFileName = await generateUniqueFileName(folderHandleRef.current, zipFileName);
208
+ const fileHandle = await folderHandleRef.current.getFileHandle(finalZipFileName, { create: true });
209
+ const writable = await fileHandle.createWritable();
210
+ await writable.write(zipBlob);
211
+ await writable.close();
212
+ }
213
+ catch (err) {
214
+ console.error('Errore nel salvataggio ZIP nella cartella, fallback al download standard:', err);
215
+ // Fallback: download standard del browser
216
+ ZipManager.downloadBlob(zipBlob, zipFileName);
217
+ }
218
+ }
219
+ else {
220
+ // Se non c'è un handle della cartella: download zip standard del browser
221
+ ZipManager.downloadBlob(zipBlob, zipFileName);
222
+ }
223
+ }
224
+ }
225
+ else {
226
+ TMMessageBoxManager.show({ message: 'Modalità di esportazione non supportata.', buttons: [ButtonNames.OK] });
227
+ return;
228
+ }
229
+ onClose();
230
+ };
231
+ // ---- Layout salva/rimuovi ----
232
+ const saveLayout = () => {
233
+ const { zipPassword, ...settingsToSave } = settings;
234
+ SDKUI_Globals.userSettings.documentDownloadSettings = { ...settingsToSave, zipPassword: '' };
235
+ const defaults = new DocumentDownloadSettings();
236
+ const hasChanges = JSON.stringify(settings) !== JSON.stringify(defaults);
237
+ if (hasChanges) {
238
+ setHasSavedLayout(true);
239
+ ShowAlert({ mode: 'success', message: 'Layout salvato con successo', title: 'Successo', duration: 3000 });
240
+ }
241
+ };
242
+ const removeLayout = () => {
243
+ const defaults = new DocumentDownloadSettings();
244
+ SDKUI_Globals.userSettings.documentDownloadSettings = { ...defaults };
245
+ setSettings(defaults);
246
+ folderHandleRef.current = null;
247
+ setHasSavedLayout(false);
248
+ ShowAlert({ mode: 'success', message: 'Layout rimosso con successo', title: 'Successo', duration: 3000 });
249
+ };
250
+ const isLayoutSameAsSaved = () => {
251
+ const saved = SDKUI_Globals.userSettings.documentDownloadSettings;
252
+ if (!saved) {
253
+ const defaults = new DocumentDownloadSettings();
254
+ return JSON.stringify(settings) === JSON.stringify(defaults);
255
+ }
256
+ return JSON.stringify(settings) === JSON.stringify(saved);
257
+ };
258
+ // ---- Render della sezione configurazione ----
259
+ const configSection = (_jsxs("div", { style: {
260
+ position: 'relative',
261
+ border: `1px solid ${TMColors.border_normal}`,
262
+ borderRadius: '8px',
263
+ padding: '10px 6px 6px 6px',
264
+ height: showTMRelationViewer ? '100%' : undefined,
265
+ flex: showTMRelationViewer ? undefined : 1,
266
+ minHeight: 0,
267
+ marginTop: '8px',
268
+ display: 'flex',
269
+ flexDirection: 'column',
270
+ boxSizing: 'border-box'
271
+ }, children: [_jsx("span", { style: {
272
+ ...getFloatingLabelStyle(),
273
+ fontWeight: 600
274
+ }, children: "Parametri di configurazione" }), _jsxs("div", { style: {
275
+ position: 'absolute',
276
+ top: '-8px',
277
+ right: '12px',
278
+ display: 'flex',
279
+ alignItems: 'center',
280
+ gap: '4px',
281
+ backgroundColor: 'white',
282
+ padding: '0 4px',
283
+ zIndex: 1
284
+ }, children: [_jsx(TMButton, { btnStyle: "toolbar", icon: _jsx(IconSave, {}), caption: "Salva Layout", color: "success", disabled: isLayoutSameAsSaved(), onClick: saveLayout }), hasSavedLayout && (_jsx(TMButton, { btnStyle: "toolbar", icon: _jsx(IconDelete, {}), caption: "Rimuovi Layout", color: "error", onClick: removeLayout }))] }), _jsxs("div", { style: {
285
+ display: 'flex',
286
+ flexDirection: 'column',
287
+ flex: 1,
288
+ overflowY: 'auto',
289
+ minHeight: 0,
290
+ }, children: [_jsx("div", { style: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, children: _jsx(TMRadioButton, { dataSource: [
291
+ { value: 'copy', display: 'Copia in una cartella' },
292
+ { value: 'zip', display: 'Comprimi in un file zip' }
293
+ ], value: settings.exportMode, direction: "row", onValueChanged: (value) => updateSettings('exportMode', value) }) }), isDirectoryPickerSupported() ? (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '4px' }, children: [_jsx(TMTextBox, { label: "Percorso", value: settings.destinationFolder, validationItems: folderValidationItems, onValueChanged: handleFolderValueChange, readOnly: true, placeHolder: "Download", onClick: handleSelectFolder, buttons: [
294
+ {
295
+ icon: _jsx(IconFolderOpen, {}),
296
+ text: 'Seleziona cartella',
297
+ onClick: handleSelectFolder
298
+ },
299
+ ...(!isUsingDefaultDownloads ? [{
300
+ icon: _jsx(IconUndo, {}),
301
+ text: 'Ripristina Download',
302
+ onClick: () => {
303
+ skipSelectFolderRef.current = true;
304
+ updateSettings('destinationFolder', 'Download');
305
+ folderHandleRef.current = null;
306
+ }
307
+ }] : [])
308
+ ] }), SDKUI_Globals.userSettings.documentDownloadSettings?.destinationFolder && (_jsxs("span", { style: { fontSize: '0.8rem', color: '#666', fontStyle: 'italic' }, children: ["Destinazione salvata: ", SDKUI_Globals.userSettings.documentDownloadSettings.destinationFolder] }))] })) : (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '4px' }, children: [_jsx("label", { style: { fontSize: '0.9rem', color: '#525252' }, children: "Percorso" }), _jsxs("div", { style: {
309
+ display: 'flex',
310
+ alignItems: 'center',
311
+ gap: '8px',
312
+ padding: '8px 12px',
313
+ border: `1px solid ${TMColors.border_normal}`,
314
+ borderRadius: '5px',
315
+ backgroundColor: '#fafafa',
316
+ }, children: [_jsx(IconFolderOpen, {}), _jsx("span", { style: { fontSize: '0.9rem', color: '#333' }, children: "Download" })] }), _jsx("span", { style: { fontSize: '0.8rem', color: '#888', fontStyle: 'italic' }, children: "Il browser in uso non supporta la selezione della cartella. I file verranno scaricati nella cartella Download." })] })), settings.exportMode === 'zip' && (_jsxs("div", { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: '12px' }, children: [_jsx(TMTextBox, { label: "Nome file zip", value: settings.zipFileName, validationItems: zipValidationItems, autoComplete: "one-time-code", onValueChanged: (e) => updateSettings('zipFileName', e.target.value) }), _jsx(TMTextBox, { label: "Proteggi con password (opzionale)", value: settings.zipPassword, type: "password", autoComplete: "one-time-code", onValueChanged: (e) => updateSettings('zipPassword', e.target.value) })] })), settings.exportMode === 'copy' && isDirectoryPickerSupported() && (_jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '4px', marginTop: '8px' }, children: isUsingDefaultDownloads ? (_jsx("span", { style: { fontSize: '0.8rem', color: '#888', fontStyle: 'italic' }, children: "Nella cartella Download il browser rinomina automaticamente i file duplicati." })) : (_jsxs("div", { style: { display: 'flex', flexDirection: 'row', alignItems: 'center', gap: '12px', flexWrap: 'wrap' }, children: [_jsx("label", { style: { fontSize: '0.9rem', color: '#525252', fontWeight: 500 }, children: "Se il file esiste" }), _jsx(TMRadioButton, { dataSource: [
317
+ { value: 'overwrite', display: 'Copia e sostituisci' },
318
+ { value: 'skip', display: 'Non copiare' },
319
+ { value: 'rename', display: 'Copia, ma rinomina' },
320
+ ], value: settings.fileExistsMode, direction: "row", onValueChanged: (value) => updateSettings('fileExistsMode', value) })] })) })), _jsxs("div", { style: { display: 'flex', alignItems: 'flex-end', gap: '12px', flexWrap: 'wrap' }, children: [_jsx("div", { style: { flex: '0 0 auto', minWidth: '160px' }, children: _jsx(TMDropDown, { label: "Per il nome file usa", value: settings.fileNamingMode, dataSource: [
321
+ { value: 'onlyDid', display: 'Solo DID' },
322
+ { value: 'documentTypeAndDid', display: 'Nome tipo documento e DID' },
323
+ { value: 'documentTypeAndCustomMetadata', display: 'Nome tipo documento e metadati personalizzati' },
324
+ { value: 'onlyCustomMetadata', display: 'Solo metadati personalizzati' },
325
+ ], onValueChanged: handleFileNamingModeChange }) }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' }, children: [_jsx("label", { style: { fontSize: '0.9rem', color: '#525252', whiteSpace: 'nowrap' }, children: "Carattere separatore" }), _jsx("input", { type: "text", value: settings.separatorChar, maxLength: 1, onChange: handleSeparatorChange, style: {
326
+ width: '32px',
327
+ height: '28px',
328
+ textAlign: 'center',
329
+ fontSize: '14px',
330
+ fontWeight: 500,
331
+ padding: '4px',
332
+ border: `1px solid ${TMColors.border_normal}`,
333
+ borderRadius: '5px',
334
+ outline: 'none',
335
+ color: 'black',
336
+ background: 'white',
337
+ }, onFocus: (e) => {
338
+ e.target.style.backgroundImage = 'linear-gradient(white, #E4E9F7)';
339
+ e.target.style.borderBottom = `2px solid ${TMColors.primary}`;
340
+ }, onBlur: (e) => {
341
+ e.target.style.backgroundImage = 'none';
342
+ e.target.style.borderBottom = `1px solid ${TMColors.border_normal}`;
343
+ } })] }), _jsx(TMCheckBox, { label: "Rimuovi la firma se presente", value: settings.removeSignature, onValueChanged: (value) => updateSettings('removeSignature', value) })] }), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: '12px' }, children: [_jsx(TMInvoiceRetrieveFormats, { width: '100%', label: SDKUI_Localizator.ElectronicInvoice + ' - ' + SDKUI_Localizator.DisplayFormat, onValueChanged: (newValue) => updateSettings('invoiceFormat', newValue), value: settings.invoiceFormat, valueOrig: settings.invoiceFormat }), _jsx(TMOrderRetrieveFormats, { width: '100%', label: SDKUI_Localizator.ElectronicOrder + ' - ' + SDKUI_Localizator.DisplayFormat, value: settings.orderFormat, valueOrig: settings.orderFormat, onValueChanged: (newValue) => updateSettings('orderFormat', newValue) })] })] })] }));
344
+ return (_jsx(TMModal, { width: calcResponsiveSizes(deviceType, showTMRelationViewer ? '95%' : '780px', showTMRelationViewer ? '95%' : '780px', '95%'), height: calcResponsiveSizes(deviceType, showTMRelationViewer ? '95%' : '450px', showTMRelationViewer ? '95%' : '450px', '95%'), title: getTitle(), onClose: onClose, showCloseButton: true, children: _jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showWaitPanel, showWaitPanelPrimary: showPrimary, showWaitPanelSecondary: showSecondary, waitPanelTitle: waitPanelTitle, waitPanelTextPrimary: waitPanelTextPrimary, waitPanelValuePrimary: waitPanelValuePrimary, waitPanelMaxValuePrimary: waitPanelMaxValuePrimary, waitPanelTextSecondary: waitPanelTextSecondary, waitPanelValueSecondary: waitPanelValueSecondary, waitPanelMaxValueSecondary: waitPanelMaxValueSecondary, isCancelable: true, abortController: abortController, children: _jsxs("div", { onContextMenu: (e) => e.preventDefault(), style: { display: 'flex', flexDirection: 'column', padding: '4px 4px 16px 4px', width: '100%', height: '100%', boxSizing: 'border-box', overflow: 'hidden' }, children: [showTMRelationViewer ? (_jsx("div", { style: { flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }, children: _jsxs(TMSplitterLayout, { direction: 'vertical', showSeparator: true, separatorSize: 8, separatorColor: 'transparent', separatorActiveColor: 'transparent', overflow: 'hidden', min: SPLITTER_MIN, start: SPLITTER_START_60_40, children: [_jsx(TMDownloadRelationViewerSection, { selectedDcmtInfos: selectedDcmtInfos, onSelectionChanged: setSelectedItemsRelationViewer, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), configSection] }, "TMCopyToFolder-relation-config") })) : (configSection), _jsx("div", { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', flexShrink: 0, marginTop: '12px' }, children: _jsx(TMButton, { caption: "Esegui", icon: _jsx(IconPlay, {}), color: 'success', showTooltip: false, disabled: !isFormValid() || (showTMRelationViewer && selectedItemsRelationViewer.filter(i => i.isDcmt).length === 0), onClick: run }) })] }) }) }));
345
+ };
346
+ export default TMCopyToFolderForm;
@@ -23,6 +23,7 @@ interface ITMDcmtFormProps {
23
23
  showHeader?: boolean;
24
24
  showBackButton?: boolean;
25
25
  showDcmtFormSidebar?: boolean;
26
+ showTodoDcmtForm?: boolean;
26
27
  isExpertMode?: boolean;
27
28
  isClosable?: boolean;
28
29
  isModal?: boolean;
@@ -57,7 +57,7 @@ export var InvocationContext;
57
57
  let abortControllerLocal = new AbortController();
58
58
  ;
59
59
  //#endregion
60
- const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMode = FormModes.Update, invocationContext = InvocationContext.Default, showHeader = true, showBackButton = true, showDcmtFormSidebar = true, isClosable = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, isModal = false, titleModal, widthModal = "100%", heightModal = "100%", allowNavigation = true, canNext, canPrev, count, itemIndex, onNext, onPrev, inputFile = null, inputMids = [], connectorFileSave = undefined, isSharedDcmt = false, sharedSourceTID, sharedSourceDID, allowRelations = true, allowButtonsRefs = false, openS4TViewer = false, enableDragDropOverlay = false, onClose, onSavedAsyncCallback, onSaveRecents, onWFOperationCompleted, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, onTaskCompleted, onTaskCreateRequest, moreInfoTasks, taskFormDialogComponent, handleNavigateToWGs, handleNavigateToDossiers, onReferenceClick, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor, s4TViewerDialogComponent, onScanRequest, passToSearch, datagridUtility }) => {
60
+ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMode = FormModes.Update, invocationContext = InvocationContext.Default, showHeader = true, showBackButton = true, showDcmtFormSidebar = true, isClosable = false, showTodoDcmtForm = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, isModal = false, titleModal, widthModal = "100%", heightModal = "100%", allowNavigation = true, canNext, canPrev, count, itemIndex, onNext, onPrev, inputFile = null, inputMids = [], connectorFileSave = undefined, isSharedDcmt = false, sharedSourceTID, sharedSourceDID, allowRelations = true, allowButtonsRefs = false, openS4TViewer = false, enableDragDropOverlay = false, onClose, onSavedAsyncCallback, onSaveRecents, onWFOperationCompleted, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, onTaskCompleted, onTaskCreateRequest, moreInfoTasks, taskFormDialogComponent, handleNavigateToWGs, handleNavigateToDossiers, onReferenceClick, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor, s4TViewerDialogComponent, onScanRequest, passToSearch, datagridUtility }) => {
61
61
  const { onRefreshSearchAsyncDatagrid, onRefreshBlogDatagrid, onRefreshPreviewDatagrid } = datagridUtility || {};
62
62
  const floatingBarContainerRef = useRef(null);
63
63
  const [id, setID] = useState('');
@@ -91,6 +91,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
91
91
  const formDataRef = useRef([]);
92
92
  const fromDTDRef = useRef();
93
93
  const dcmtFileRef = useRef(null);
94
+ const metadataDcmtOriginRef = useRef(null);
94
95
  const [isOpenDistinctValues, setIsOpenDistinctValues] = useState(false);
95
96
  const [isOpenFormulaEditor, setIsOpenFormulaEditor] = useState(false);
96
97
  const [currentTIDHasDetailRelations, setCurrentTIDHasDetailRelations] = useState();
@@ -135,7 +136,30 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
135
136
  if (!did)
136
137
  return;
137
138
  TMSpinner.show({ description: 'Loading Metadata...' });
138
- let res = getMetadataResult ?? await SDK_Globals.tmSession?.NewSearchEngine().GetMetadataAsync(TID, did, true);
139
+ let res = getMetadataResult;
140
+ if (!res) {
141
+ try {
142
+ res = await SDK_Globals.tmSession?.NewSearchEngine().GetMetadataAsync(TID, did, true);
143
+ }
144
+ catch (metadataError) {
145
+ // Estrai ErrorCode dal campo detail se disponibile
146
+ let errorCode = undefined;
147
+ if (metadataError?.isApiException && metadataError?.response?.detail) {
148
+ try {
149
+ const detailObj = JSON.parse(metadataError.response.detail);
150
+ errorCode = detailObj?.ErrorCode;
151
+ }
152
+ catch (parseError) {
153
+ console.log("Impossibile parsare il detail dell'eccezione:", parseError);
154
+ }
155
+ }
156
+ // Se ErrorCode è -5, ignora silenziosamente, altrimenti mostra l'eccezione originale
157
+ if (errorCode !== -5) {
158
+ TMExceptionBoxManager.show({ exception: metadataError });
159
+ }
160
+ return;
161
+ }
162
+ }
139
163
  const origin = { fromName: res?.fromName, fromTID: res?.fromTID };
140
164
  let dtd = res?.dtdResult;
141
165
  let rows = dtd.rows ? dtd.rows[0] : [];
@@ -307,7 +331,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
307
331
  }
308
332
  else {
309
333
  const renderedMetadata = dtd?.metadata?.filter((metadata) => handleArchiveVisibility(metadata)) ?? [];
310
- const metadataList = searchResultToMetadataValues(dtd?.id, undefined, [], [], renderedMetadata, layoutMode, isReadOnlyOriginCallback(metadataDcmtOrigin?.fromTID));
334
+ const metadataList = searchResultToMetadataValues(dtd?.id, undefined, [], [], renderedMetadata, layoutMode, isReadOnlyOriginCallback(metadataDcmtOriginRef.current?.fromTID));
311
335
  setFormDataOrig(structuredClone(metadataList));
312
336
  setFormData(structuredClone(metadataList));
313
337
  formDataOrigRef.current = structuredClone(metadataList);
@@ -322,7 +346,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
322
346
  setIsInitialLoading(false);
323
347
  setIsNavigating(false);
324
348
  }
325
- }, [TID, DID, layoutMode, inputFile, setMetadataList, handleReset, allowButtonsRefs, isReadOnlyOriginCallback, metadataDcmtOrigin?.fromTID]);
349
+ }, [TID, DID, layoutMode, inputFile, setMetadataList, handleReset, allowButtonsRefs, isReadOnlyOriginCallback]);
326
350
  const currentSearchResults = useMemo(() => {
327
351
  if (!formData || formData.length === 0 || !TID || !DID)
328
352
  return [];
@@ -477,6 +501,9 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
477
501
  useEffect(() => {
478
502
  dcmtFileRef.current = dcmtFile;
479
503
  }, [dcmtFile]);
504
+ useEffect(() => {
505
+ metadataDcmtOriginRef.current = metadataDcmtOrigin;
506
+ }, [metadataDcmtOrigin]);
480
507
  useEffect(() => {
481
508
  if (!inputFile || inputFile === null)
482
509
  return;
@@ -775,7 +802,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
775
802
  // Verifica che ci siano riferimenti renderizzabili (solo Dossier o WorkingGroup)
776
803
  return dcmtReferences.some(ref => ref.objClass === ObjectClasses.Dossier || ref.objClass === ObjectClasses.WorkingGroup);
777
804
  }, [allowButtonsRefs, layoutMode, dcmtReferences, isOpenDetails, isOpenMaster]);
778
- const isToppyVisible = useMemo(() => Boolean((showToppyForApprove || showToppyForCompleteMoreInfo || showToppyForReferences) && !openS4TViewer), [showToppyForApprove, showToppyForCompleteMoreInfo, showToppyForReferences, openS4TViewer]);
805
+ const isToppyVisible = useMemo(() => Boolean((showToppyForApprove || showToppyForCompleteMoreInfo || showToppyForReferences) && !openS4TViewer && !showTodoDcmtForm), [showToppyForApprove, showToppyForCompleteMoreInfo, showToppyForReferences, openS4TViewer, showTodoDcmtForm]);
779
806
  const isModified = useMemo(() => calcIsModified(formData, formDataOrig), [formData, formDataOrig]);
780
807
  const formToolbar = useMemo(() => _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [allowNavigation && canPrev != undefined && _jsx("p", { style: { textAlign: 'center', padding: '1px 4px', display: 'flex' }, children: `${itemIndex}/${count}` }), allowNavigation && canPrev != undefined && _jsx(TMSaveFormButtonPrevious, { btnStyle: 'icon', iconColor: 'white', isModified: isModified, formMode: formMode, canPrev: canPrev, onPrev: onPrev }), allowNavigation && canNext != undefined && _jsx(TMSaveFormButtonNext, { btnStyle: 'icon', iconColor: 'white', isModified: isModified, formMode: formMode, canNext: canNext, onNext: onNext }), layoutMode === LayoutModes.Update &&
781
808
  _jsx(ContextMenu, { items: operationItems, trigger: "left", children: _jsx(IconMenuVertical, { color: 'white', cursor: 'pointer' }) }), layoutMode === LayoutModes.Ark &&
@@ -844,7 +871,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
844
871
  const handleArchiveCompleted = useCallback(async () => {
845
872
  let firstBlock = true;
846
873
  let maxFileSize = 0;
847
- let operationTitle = 'Archiviazione';
874
+ let operationTitle = SDKUI_Localizator.Archiving;
848
875
  setUseWaitPanelLocalState(true);
849
876
  setShowWaitPanelLocal(true);
850
877
  setShowPrimaryLocal(false);
@@ -893,7 +920,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
893
920
  firstBlock = false;
894
921
  }
895
922
  setWaitPanelValueSecondaryLocal(pd.ProgressBarValue);
896
- setWaitPanelTextSecondaryLocal(`Archiviazione... ${Globalization.getNumberDisplayValue(pd.ProgressBarValue, true)} / ${Globalization.getNumberDisplayValue(maxFileSize, true)}`);
923
+ setWaitPanelTextSecondaryLocal(`${SDKUI_Localizator.Archiving}... ${Globalization.getNumberDisplayValue(pd.ProgressBarValue, true)} / ${Globalization.getNumberDisplayValue(maxFileSize, true)}`);
897
924
  if (pd.ProgressBarValue === pd.ProgressBarMaximum) {
898
925
  setWaitPanelMaxValueSecondaryLocal(0);
899
926
  setWaitPanelValueSecondaryLocal(0);
@@ -1016,6 +1043,21 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1016
1043
  fd.tid = TID;
1017
1044
  return fd;
1018
1045
  }, [focusedMetadataValue?.value, focusedMetadataValue?.mid, TID]);
1046
+ /**
1047
+ * Restituisce l'handler onBack per i pannelli, evitando duplicazione di codice.
1048
+ * @param isMainPanel - Se true, è il pannello principale (tmDcmtForm)
1049
+ */
1050
+ const getOnBackHandler = (isMainPanel = false) => {
1051
+ // Se showBackButton è false, non mostrare mai il back
1052
+ if (showBackButton === false)
1053
+ return undefined;
1054
+ // Mobile: mostra back su tutti i pannelli (se showBackButton è definito e non è closable)
1055
+ if (isMobile) {
1056
+ return (showBackButton !== undefined && !isClosable) ? handleClose : undefined;
1057
+ }
1058
+ // Desktop: mostra back solo sul pannello principale (se showBackButton è definito e non è closable)
1059
+ return (showBackButton !== undefined && isMainPanel && !isClosable) ? handleClose : undefined;
1060
+ };
1019
1061
  // Determina se showAll deve essere automaticamente true
1020
1062
  // Best practice: usa useMemo per calcolare valori derivati invece di useEffect con setState
1021
1063
  const shouldShowAll = useMemo(() => {
@@ -1100,7 +1142,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1100
1142
  ]);
1101
1143
  const tmBlog = useMemo(() => _jsx(TMDcmtBlog, { tid: TID, did: DID, fetchBlogDataTrigger: refreshBlogTrigger, onRefreshBlogDatagrid: onRefreshBlogDatagrid, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), [TID, DID, allTasks, refreshBlogTrigger, handleNavigateToWGs, handleNavigateToDossiers]);
1102
1144
  const tmSysMetadata = useMemo(() => _jsx(TMMetadataValues, { layoutMode: layoutMode, openChooserBySingleClick: !isOpenDistinctValues, TID: TID, isReadOnly: true, deviceType: deviceType, metadataValues: formData.filter(o => (o.mid != undefined && o.mid <= 100)), metadataValuesOrig: formData.filter(o => (o.mid != undefined && o.mid <= 100)), validationItems: [], inputMids: inputMids }), [TID, layoutMode, formData, deviceType, inputMids]);
1103
- const tmDcmtPreview = useMemo(() => _jsx(TMDcmtPreviewWrapper, { refreshPreviewTrigger: refreshPreviewTrigger, fromDTD: fromDTD, currentDcmt: currentDcmt, dcmtFile: dcmtFile ?? inputFile, deviceType: deviceType, layoutMode: layoutMode, onFileUpload: (file) => { setDcmtFile(file); }, openFileUploaderPdfEditor: openFileUploaderPdfEditor, enableDragDropOverlay: enableDragDropOverlay, onScanRequest: onScanRequest }), [currentDcmt, dcmtFile, deviceType, fromDTD, layoutMode, inputFile, enableDragDropOverlay, setDcmtFile, onScanRequest, openFileUploaderPdfEditor, refreshPreviewTrigger]);
1145
+ const tmDcmtPreview = useMemo(() => _jsx(TMDcmtPreviewWrapper, { refreshPreviewTrigger: refreshPreviewTrigger, fromDTD: fromDTD, currentDcmt: currentDcmt, dcmtFile: dcmtFile ?? inputFile, deviceType: deviceType, onBack: getOnBackHandler(), layoutMode: layoutMode, onFileUpload: (file) => { setDcmtFile(file); }, openFileUploaderPdfEditor: openFileUploaderPdfEditor, enableDragDropOverlay: enableDragDropOverlay, onScanRequest: onScanRequest }), [currentDcmt, dcmtFile, deviceType, fromDTD, layoutMode, inputFile, enableDragDropOverlay, setDcmtFile, onScanRequest, openFileUploaderPdfEditor, refreshPreviewTrigger]);
1104
1146
  const tmWF = useMemo(() => {
1105
1147
  if (isWFDataLoading) {
1106
1148
  return (_jsx("div", { style: {
@@ -1171,7 +1213,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1171
1213
  did: Number(DID),
1172
1214
  name: fromDTD?.nameLoc ?? SDKUI_Localizator.Widget_Activities,
1173
1215
  },
1174
- }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, afterTaskSaved: afterTaskSaved, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }));
1216
+ }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, afterTaskSaved: afterTaskSaved, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, onBack: getOnBackHandler() }));
1175
1217
  }, [allTasks, TID, DID, fromDTD]);
1176
1218
  const normalizedTID = TID !== undefined ? Number(TID) : undefined;
1177
1219
  const defaultPanelDimensions = {
@@ -1230,7 +1272,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1230
1272
  showHeader: showHeader,
1231
1273
  title: titleDcmtFormPanel,
1232
1274
  allowMaximize: !isMobile,
1233
- onBack: showBackButton ? (isClosable && deviceType !== DeviceType.MOBILE) ? undefined : handleClose : undefined,
1275
+ onBack: getOnBackHandler(true),
1234
1276
  onClose: isClosable ? () => { } : undefined,
1235
1277
  toolbar: allowNavigation ? formToolbar : _jsx(_Fragment, {})
1236
1278
  },
@@ -1245,7 +1287,14 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1245
1287
  {
1246
1288
  id: 'tmBlog',
1247
1289
  name: SDKUI_Localizator.BlogCase,
1248
- contentOptions: { component: tmBlog, panelContainer: { title: SDKUI_Localizator.BlogCase, allowMaximize: !isMobile } },
1290
+ contentOptions: {
1291
+ component: tmBlog,
1292
+ panelContainer: {
1293
+ title: SDKUI_Localizator.BlogCase,
1294
+ allowMaximize: !isMobile,
1295
+ onBack: getOnBackHandler(),
1296
+ }
1297
+ },
1249
1298
  toolbarOptions: {
1250
1299
  icon: _jsx(IconBoard, { fontSize: 24 }),
1251
1300
  visible: getDcmtFormToolbarVisibility(SDK_Globals.tmSession?.SessionDescr?.appModuleID ?? AppModules.SURFER).tmBlog,
@@ -1257,7 +1306,14 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1257
1306
  {
1258
1307
  id: 'tmSysMetadata',
1259
1308
  name: SDKUI_Localizator.MetadataSystem,
1260
- contentOptions: { component: tmSysMetadata, panelContainer: { title: SDKUI_Localizator.MetadataSystem, allowMaximize: !isMobile } },
1309
+ contentOptions: {
1310
+ component: tmSysMetadata,
1311
+ panelContainer: {
1312
+ title: SDKUI_Localizator.MetadataSystem,
1313
+ allowMaximize: !isMobile,
1314
+ onBack: getOnBackHandler(),
1315
+ }
1316
+ },
1261
1317
  toolbarOptions: { icon: _jsx(IconDcmtTypeSys, { fontSize: 24 }), visible: getDcmtFormToolbarVisibility(SDK_Globals.tmSession?.SessionDescr?.appModuleID ?? AppModules.SURFER).tmSysMetadata, disabled: isSysMetadataDisabled, orderNumber: 3, isActive: allInitialPanelVisibility['tmSysMetadata'] }
1262
1318
  },
1263
1319
  {
@@ -1278,7 +1334,8 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1278
1334
  contentOptions: {
1279
1335
  component: tmWF,
1280
1336
  panelContainer: {
1281
- title: "Workflow", allowMaximize: !isMobile
1337
+ title: "Workflow", allowMaximize: !isMobile,
1338
+ onBack: getOnBackHandler(),
1282
1339
  }
1283
1340
  },
1284
1341
  toolbarOptions: {
@@ -1537,38 +1594,59 @@ const validateMaxLength = (mvd, value, validationItems) => {
1537
1594
  //#endregion Validation
1538
1595
  // Synchronizes panel visibility and toolbar button disabled states when panels become disabled
1539
1596
  const PanelDisabledStateHandler = ({ isWFDisabled, isSysMetadataDisabled, isBoardDisabled, isDcmtTasksDisabled, isPreviewDisabled }) => {
1540
- const { setPanelVisibilityById, setToolbarButtonDisabled, panelVisibility } = useTMPanelManagerContext();
1597
+ const { setPanelVisibilityById, setToolbarButtonDisabled } = useTMPanelManagerContext();
1541
1598
  useEffect(() => {
1542
- // Aggiorna lo stato disabled del bottone toolbar
1543
- setToolbarButtonDisabled('tmSysMetadata', isSysMetadataDisabled);
1544
- setToolbarButtonDisabled('tmBlog', isBoardDisabled);
1545
- setToolbarButtonDisabled('tmWF', isWFDisabled);
1546
- setToolbarButtonDisabled('tmDcmtTasks', isDcmtTasksDisabled);
1547
- setToolbarButtonDisabled('tmDcmtPreview', isPreviewDisabled);
1548
- // Chiude il pannello solo se è attualmente visibile e deve essere disabilitato
1549
- if (isSysMetadataDisabled && panelVisibility['tmSysMetadata']) {
1599
+ if (isSysMetadataDisabled) {
1600
+ setToolbarButtonDisabled('tmSysMetadata', true);
1550
1601
  setPanelVisibilityById('tmSysMetadata', false);
1551
1602
  }
1552
- if (isBoardDisabled && panelVisibility['tmBlog']) {
1603
+ else {
1604
+ setToolbarButtonDisabled('tmSysMetadata', false);
1605
+ }
1606
+ }, [isSysMetadataDisabled]);
1607
+ useEffect(() => {
1608
+ if (isBoardDisabled) {
1609
+ setToolbarButtonDisabled('tmBlog', true);
1553
1610
  setPanelVisibilityById('tmBlog', false);
1554
1611
  }
1555
- if (isWFDisabled && panelVisibility['tmWF']) {
1612
+ else {
1613
+ setToolbarButtonDisabled('tmBlog', false);
1614
+ }
1615
+ }, [isBoardDisabled]);
1616
+ useEffect(() => {
1617
+ if (isWFDisabled) {
1618
+ setToolbarButtonDisabled('tmWF', true);
1556
1619
  setPanelVisibilityById('tmWF', false);
1557
1620
  }
1558
- if (isDcmtTasksDisabled && panelVisibility['tmDcmtTasks']) {
1621
+ else {
1622
+ setToolbarButtonDisabled('tmWF', false);
1623
+ }
1624
+ }, [isWFDisabled]);
1625
+ useEffect(() => {
1626
+ if (isDcmtTasksDisabled) {
1627
+ setToolbarButtonDisabled('tmDcmtTasks', true);
1559
1628
  setPanelVisibilityById('tmDcmtTasks', false);
1560
1629
  }
1561
- if (isPreviewDisabled && panelVisibility['tmDcmtPreview']) {
1630
+ else {
1631
+ setToolbarButtonDisabled('tmDcmtTasks', false);
1632
+ }
1633
+ }, [isDcmtTasksDisabled]);
1634
+ useEffect(() => {
1635
+ if (isPreviewDisabled) {
1636
+ setToolbarButtonDisabled('tmDcmtPreview', true);
1562
1637
  setPanelVisibilityById('tmDcmtPreview', false);
1563
1638
  }
1564
- }, [isSysMetadataDisabled, isBoardDisabled, isWFDisabled, isDcmtTasksDisabled, isPreviewDisabled, setPanelVisibilityById, setToolbarButtonDisabled, panelVisibility]);
1639
+ else {
1640
+ setToolbarButtonDisabled('tmDcmtPreview', false);
1641
+ }
1642
+ }, [isPreviewDisabled]);
1565
1643
  return null;
1566
1644
  };
1567
- const TMDcmtPreviewWrapper = ({ refreshPreviewTrigger, fromDTD, currentDcmt, layoutMode, dcmtFile, deviceType, isVisible, onFileUpload, openFileUploaderPdfEditor, enableDragDropOverlay = false, onScanRequest }) => {
1645
+ const TMDcmtPreviewWrapper = ({ refreshPreviewTrigger, fromDTD, currentDcmt, layoutMode, dcmtFile, deviceType, isVisible, onFileUpload, openFileUploaderPdfEditor, enableDragDropOverlay = false, onScanRequest, onBack }) => {
1568
1646
  const { setPanelVisibilityById, toggleMaximize, isResizingActive, countVisibleLeafPanels, panelVisibility } = useTMPanelManagerContext();
1569
1647
  const isMobile = deviceType === DeviceType.MOBILE;
1570
1648
  return (layoutMode === LayoutModes.Update ?
1571
- _jsx(TMDcmtPreview, { dcmtData: currentDcmt, isVisible: isVisible, onClosePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('tmDcmtPreview', false) : undefined, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => toggleMaximize("tmDcmtPreview") : undefined, isResizingActive: isResizingActive }, refreshPreviewTrigger) :
1649
+ _jsx(TMDcmtPreview, { dcmtData: currentDcmt, isVisible: isVisible, onClosePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('tmDcmtPreview', false) : undefined, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => toggleMaximize("tmDcmtPreview") : undefined, onBack: onBack, isResizingActive: isResizingActive }, refreshPreviewTrigger) :
1572
1650
  _jsx(TMFileUploader, { fromDTD: fromDTD, onFileUpload: onFileUpload, openFileUploaderPdfEditor: openFileUploaderPdfEditor, onClose: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('tmDcmtPreview', false) : undefined, isRequired: fromDTD?.archiveConstraint === ArchiveConstraints.ContentCompulsory && dcmtFile === null, defaultBlob: dcmtFile, deviceType: deviceType, isResizingActive: isResizingActive, enableDragDropOverlay: panelVisibility['tmDcmtPreview'] && enableDragDropOverlay, onScanRequest: onScanRequest }));
1573
1651
  };
1574
1652
  const Ribbon = styled.div `