@topconsultnpm/sdkui-react 6.21.0-dev2.37 → 6.21.0-dev2.39

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.
@@ -16,6 +16,8 @@ interface ITMUserChooserProps extends ITMChooserProps {
16
16
  initialShowChooser?: boolean;
17
17
  /** Allow showing all users with toggle button */
18
18
  allowShowAllUsers?: boolean;
19
+ /** If true, uses UserListCacheService.GetAllAdminAsync() instead of GetAllAsync() */
20
+ adminMode?: boolean;
19
21
  /** Funzione per aggiornare lo stato di apertura della modale */
20
22
  updateIsModalOpen?: (isOpen: boolean) => void;
21
23
  }
@@ -30,6 +32,8 @@ interface ITMUserChooserFormProps extends ITMChooserFormProps<UserDescriptor> {
30
32
  hideShowId?: boolean;
31
33
  /** Allow showing all users with toggle button */
32
34
  allowShowAllUsers?: boolean;
35
+ /** If true, uses UserListCacheService.GetAllAdminAsync() instead of GetAllAsync() */
36
+ adminMode?: boolean;
33
37
  }
34
38
  export declare const TMUserChooserForm: React.FunctionComponent<ITMUserChooserFormProps>;
35
39
  export declare const TMUserIcon: ({ ud }: {
@@ -8,7 +8,7 @@ import TMSummary from '../editors/TMSummary';
8
8
  import TMChooserForm from '../forms/TMChooserForm';
9
9
  import TMButton from '../base/TMButton';
10
10
  import TMDataUserIdItemViewer from '../viewers/TMDataUserIdItemViewer';
11
- const TMUserChooser = ({ labelColor, titleForm, filter, readOnly = false, icon, width, dataSource, backgroundColor, openChooserBySingleClick, buttons = [], disabled = false, showBorder = true, hideRefresh = false, hideShowId = false, elementStyle, allowMultipleSelection, values, isModifiedWhen, label, placeHolder, validationItems = [], onValueChanged, showClearButton, initialShowChooser = false, allowShowAllUsers = false, updateIsModalOpen }) => {
11
+ const TMUserChooser = ({ labelColor, titleForm, filter, readOnly = false, icon, width, dataSource, backgroundColor, openChooserBySingleClick, buttons = [], disabled = false, showBorder = true, hideRefresh = false, hideShowId = false, elementStyle, allowMultipleSelection, values, isModifiedWhen, label, placeHolder, validationItems = [], onValueChanged, showClearButton, initialShowChooser = false, allowShowAllUsers = false, adminMode = false, updateIsModalOpen }) => {
12
12
  const [showChooser, setShowChooser] = useState(initialShowChooser);
13
13
  useEffect(() => {
14
14
  setShowChooser(initialShowChooser);
@@ -24,14 +24,14 @@ const TMUserChooser = ({ labelColor, titleForm, filter, readOnly = false, icon,
24
24
  updateIsModalOpen?.(true);
25
25
  }
26
26
  }, elementStyle: elementStyle, isModifiedWhen: isModifiedWhen, openEditorOnSummaryClick: openChooserBySingleClick, label: label, template: renderTemplate(), onClearClick: showClearButton ? () => { onValueChanged?.([]); } : undefined, validationItems: validationItems }), showChooser &&
27
- _jsx(TMUserChooserForm, { title: titleForm, allowMultipleSelection: allowMultipleSelection, hasShowOnlySelectedItems: true, dataSource: dataSource, filter: filter, selectedIDs: values, hideRefresh: hideRefresh, hideShowId: hideShowId, allowShowAllUsers: allowShowAllUsers, onClose: () => {
27
+ _jsx(TMUserChooserForm, { title: titleForm, allowMultipleSelection: allowMultipleSelection, hasShowOnlySelectedItems: true, dataSource: dataSource, filter: filter, selectedIDs: values, hideRefresh: hideRefresh, hideShowId: hideShowId, allowShowAllUsers: allowShowAllUsers, adminMode: adminMode, onClose: () => {
28
28
  setShowChooser(false);
29
29
  summaryInputRef.current?.focus();
30
30
  updateIsModalOpen?.(false);
31
31
  }, onChoose: (IDs) => { onValueChanged?.(IDs); } })] }));
32
32
  };
33
33
  export default TMUserChooser;
34
- export const TMUserChooserForm = ({ allowMultipleSelection, columns, hideRefresh = false, hideShowId = false, startWithShowOnlySelectedItems = true, filter, title, hasShowOnlySelectedItems, width, height, selectedIDs, dataSource, onClose, onChoose, allowShowAllUsers = false }) => {
34
+ export const TMUserChooserForm = ({ allowMultipleSelection, columns, hideRefresh = false, hideShowId = false, startWithShowOnlySelectedItems = true, filter, title, hasShowOnlySelectedItems, width, height, selectedIDs, dataSource, onClose, onChoose, allowShowAllUsers = false, adminMode = false }) => {
35
35
  const [currentDataSource, setCurrentDataSource] = useState(dataSource);
36
36
  const [showingAllUsers, setShowingAllUsers] = useState(false);
37
37
  const dataColumns = useMemo(() => {
@@ -45,8 +45,10 @@ export const TMUserChooserForm = ({ allowMultipleSelection, columns, hideRefresh
45
45
  const getItems = async (refreshCache) => {
46
46
  TMSpinner.show({ description: `${SDKUI_Localizator.Loading} - ${SDK_Localizator.Users} ...` });
47
47
  if (refreshCache)
48
- UserListCacheService.RemoveAll();
49
- let allUsers = await UserListCacheService.GetAllAsync();
48
+ adminMode ? UserListCacheService.RemoveAllAdmin() : UserListCacheService.RemoveAll();
49
+ let allUsers = adminMode
50
+ ? await UserListCacheService.GetAllAdminAsync()
51
+ : await UserListCacheService.GetAllAsync();
50
52
  let users = filter ? allUsers?.filter(filter) : allUsers;
51
53
  TMSpinner.hide();
52
54
  return users;
@@ -1,11 +1,19 @@
1
1
  import React from 'react';
2
2
  import { DcmtInfo } from '../../../ts';
3
+ import { HomeBlogPost, TaskDescriptor } from '@topconsultnpm/sdk-ts';
3
4
  import { TMCopyToFolderMode } from '../../../hooks/useDocumentOperations';
4
5
  interface ITMCopyToFolderFormProps {
5
6
  mode: TMCopyToFolderMode;
6
7
  selectedDcmtInfos: Array<DcmtInfo>;
7
8
  onClose: () => void;
8
9
  showTMRelationViewer: boolean;
10
+ allTasks?: Array<TaskDescriptor>;
11
+ getAllTasks?: () => Promise<void>;
12
+ deleteTaskByIdsCallback?: (deletedTaskIds: Array<number>) => Promise<void>;
13
+ addTaskCallback?: (task: TaskDescriptor) => Promise<void>;
14
+ editTaskCallback?: (task: TaskDescriptor) => Promise<void>;
15
+ handleNavigateToWGs?: (value: HomeBlogPost | number) => Promise<void>;
16
+ handleNavigateToDossiers?: (value: HomeBlogPost | number) => Promise<void>;
9
17
  }
10
18
  /**
11
19
  * Form per la copia/zip dei documenti in una cartella locale.
@@ -19,13 +19,13 @@ import TMCheckBox from '../../editors/TMCheckBox';
19
19
  import ShowAlert from '../../base/TMAlert';
20
20
  import { TMColors } from '../../../utils/theme';
21
21
  import TMDownloadRelationViewerSection from './TMDownloadRelationViewerSection';
22
- import { buildInitialDownloadSettings, fileExists, generateTargetFileName, generateUniqueFileName, getDcmtInfosToDownload, getFloatingLabelStyle, isDirectoryPickerSupported, SPLITTER_MIN, SPLITTER_START_HALF, } from './copyAndMergeDcmtsShared';
22
+ import { buildInitialDownloadSettings, fileExists, generateTargetFileName, generateUniqueFileName, getDcmtInfosToDownload, getFloatingLabelStyle, isDirectoryPickerSupported, SPLITTER_MIN, SPLITTER_START_60_40, } from './copyAndMergeDcmtsShared';
23
23
  /**
24
24
  * Form per la copia/zip dei documenti in una cartella locale.
25
25
  * Logica condivisa con TMMergeToPdfForm è esternalizzata in copyAndMergeDcmtsShared
26
26
  * e TMDownloadRelationViewerSection.
27
27
  */
28
- const TMCopyToFolderForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationViewer }) => {
28
+ const TMCopyToFolderForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationViewer, allTasks, getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers }) => {
29
29
  const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, } = useDcmtOperations();
30
30
  const deviceType = useDeviceType();
31
31
  // ---- Stato dei settings ----
@@ -46,8 +46,8 @@ const TMCopyToFolderForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationVi
46
46
  const getTitle = () => {
47
47
  const count = ` (${selectedDcmtInfos.length})`;
48
48
  const modeLabelMap = {
49
- onlySelected: 'Solo i documenti selezionati',
50
- customized: 'Documenti di primo livello e i correlati selezionati',
49
+ onlySelected: 'I documenti selezionati',
50
+ customized: 'I documenti selezionati e i correlati',
51
51
  };
52
52
  const modeLabel = modeLabelMap[mode] || modeLabelMap.onlySelected;
53
53
  return `Copia in una cartella - ${modeLabel}${count}`;
@@ -195,10 +195,31 @@ const TMCopyToFolderForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationVi
195
195
  const zipFileName = settings.zipFileName.trim().toLowerCase().endsWith('.zip')
196
196
  ? settings.zipFileName.trim()
197
197
  : settings.zipFileName.trim() + '.zip';
198
- await ZipManager.createAndDownload(zipEntries, zipFileName, {
198
+ // Crea il blob ZIP
199
+ const zipBlob = await ZipManager.createZip(zipEntries, {
199
200
  compressionLevel: 6,
200
201
  password: settings.zipPassword.trim() || undefined,
201
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
+ }
202
223
  }
203
224
  }
204
225
  else {
@@ -239,18 +260,37 @@ const TMCopyToFolderForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationVi
239
260
  position: 'relative',
240
261
  border: `1px solid ${TMColors.border_normal}`,
241
262
  borderRadius: '8px',
242
- padding: '8px',
263
+ padding: '10px 6px 6px 6px',
243
264
  height: showTMRelationViewer ? '100%' : undefined,
244
265
  flex: showTMRelationViewer ? undefined : 1,
245
266
  minHeight: 0,
246
- marginTop: showTMRelationViewer ? '10px' : undefined,
267
+ marginTop: '8px',
247
268
  display: 'flex',
248
269
  flexDirection: 'column',
249
270
  boxSizing: 'border-box'
250
- }, children: [_jsx("span", { style: getFloatingLabelStyle(), title: "Parametri di configurazione", children: "Parametri di configurazione" }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '8px', overflowY: 'auto', flex: 1, width: '100%', maxWidth: '720px', alignSelf: 'center' }, children: [_jsx("div", { style: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, children: _jsx(TMRadioButton, { dataSource: [
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: [
251
291
  { value: 'copy', display: 'Copia in una cartella' },
252
292
  { value: 'zip', display: 'Comprimi in un file zip' }
253
- ], value: settings.exportMode, direction: "row", onValueChanged: (value) => updateSettings('exportMode', value) }) }), settings.exportMode === 'copy' && (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: [
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: [
254
294
  {
255
295
  icon: _jsx(IconFolderOpen, {}),
256
296
  text: 'Seleziona cartella',
@@ -273,11 +313,11 @@ const TMCopyToFolderForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationVi
273
313
  border: `1px solid ${TMColors.border_normal}`,
274
314
  borderRadius: '5px',
275
315
  backgroundColor: '#fafafa',
276
- }, 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: 'flex', gap: '12px', flexWrap: 'wrap' }, children: [_jsx("div", { style: { flex: '1 1 220px', minWidth: 0 }, children: _jsx(TMTextBox, { label: "Nome file zip", value: settings.zipFileName, validationItems: zipValidationItems, autoComplete: "one-time-code", onValueChanged: (e) => updateSettings('zipFileName', e.target.value) }) }), _jsx("div", { style: { flex: '1 1 220px', minWidth: 0 }, children: _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() && !isUsingDefaultDownloads && (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '6px' }, children: [_jsx("label", { style: { fontSize: '0.9rem', color: '#525252', fontWeight: 500 }, children: "Se il file esiste" }), _jsx(TMRadioButton, { dataSource: [
277
- { value: 'overwrite', display: 'Copia e sostituisci' },
278
- { value: 'skip', display: 'Non copiare' },
279
- { value: 'rename', display: 'Copia, ma rinomina' },
280
- ], value: settings.fileExistsMode, direction: "row", onValueChanged: (value) => updateSettings('fileExistsMode', value) })] })), _jsxs("div", { style: { display: 'flex', alignItems: 'flex-end', gap: '16px', flexWrap: 'wrap' }, children: [_jsx("div", { style: { flex: '1 1 220px', minWidth: 0 }, children: _jsx(TMDropDown, { label: "Per il nome file usa", value: settings.fileNamingMode, dataSource: [
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: [
281
321
  { value: 'onlyDid', display: 'Solo DID' },
282
322
  { value: 'documentTypeAndDid', display: 'Nome tipo documento e DID' },
283
323
  { value: 'documentTypeAndCustomMetadata', display: 'Nome tipo documento e metadati personalizzati' },
@@ -300,7 +340,7 @@ const TMCopyToFolderForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationVi
300
340
  }, onBlur: (e) => {
301
341
  e.target.style.backgroundImage = 'none';
302
342
  e.target.style.borderBottom = `1px solid ${TMColors.border_normal}`;
303
- } })] }), _jsx(TMCheckBox, { label: "Rimuovi la firma se presente", value: settings.removeSignature, onValueChanged: (value) => updateSettings('removeSignature', value) })] }), _jsxs("div", { style: { display: 'flex', gap: '12px', flexWrap: 'wrap' }, children: [_jsx("div", { style: { flex: '1 1 240px', minWidth: 0 }, children: _jsx(TMInvoiceRetrieveFormats, { width: '100%', label: SDKUI_Localizator.ElectronicInvoice + ' - ' + SDKUI_Localizator.DisplayFormat, onValueChanged: (newValue) => updateSettings('invoiceFormat', newValue), value: settings.invoiceFormat, valueOrig: settings.invoiceFormat }) }), _jsx("div", { style: { flex: '1 1 240px', minWidth: 0 }, children: _jsx(TMOrderRetrieveFormats, { width: '100%', label: SDKUI_Localizator.ElectronicOrder + ' - ' + SDKUI_Localizator.DisplayFormat, value: settings.orderFormat, valueOrig: settings.orderFormat, onValueChanged: (newValue) => updateSettings('orderFormat', newValue) }) })] })] })] }));
304
- return (_jsx(TMModal, { width: calcResponsiveSizes(deviceType, showTMRelationViewer ? '90%' : '780px', showTMRelationViewer ? '90%' : '780px', '95%'), height: calcResponsiveSizes(deviceType, showTMRelationViewer ? '90%' : '450px', showTMRelationViewer ? '90%' : '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', gap: '16px', padding: '16px', 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: 'visible', min: SPLITTER_MIN, start: SPLITTER_START_HALF, children: [_jsx(TMDownloadRelationViewerSection, { selectedDcmtInfos: selectedDcmtInfos, onSelectionChanged: setSelectedItemsRelationViewer }), configSection] }, "TMCopyToFolder-relation-config") })) : (configSection), _jsxs("div", { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', gap: '12px', flexShrink: 0 }, children: [_jsx(TMButton, { caption: "Salva Layout", icon: _jsx(IconSave, {}), color: 'primary', showTooltip: false, disabled: isLayoutSameAsSaved(), onClick: saveLayout }), hasSavedLayout && (_jsx(TMButton, { caption: "Rimuovi Layout", icon: _jsx(IconDelete, {}), color: 'tertiary', showTooltip: false, onClick: removeLayout })), _jsx(TMButton, { caption: "Esegui", icon: _jsx(IconPlay, {}), color: 'success', showTooltip: false, disabled: !isFormValid() || (showTMRelationViewer && selectedItemsRelationViewer.filter(i => i.isDcmt).length === 0), onClick: run })] })] }) }) }));
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', 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 }) })] }) }) }));
305
345
  };
306
346
  export default TMCopyToFolderForm;
@@ -1,10 +1,18 @@
1
1
  import React from 'react';
2
+ import { HomeBlogPost, TaskDescriptor } from '@topconsultnpm/sdk-ts';
2
3
  import { DcmtInfo } from '../../../ts';
3
4
  import { IRelatedDcmt } from './TMMasterDetailDcmts';
4
5
  interface ITMDownloadRelationViewerSectionProps {
5
6
  selectedDcmtInfos: Array<DcmtInfo>;
6
7
  /** Notifica al parent la lista dei documenti correlati selezionati (deduplicati) */
7
8
  onSelectionChanged: (items: Array<IRelatedDcmt>) => void;
9
+ allTasks?: Array<TaskDescriptor>;
10
+ getAllTasks?: () => Promise<void>;
11
+ deleteTaskByIdsCallback?: (deletedTaskIds: Array<number>) => Promise<void>;
12
+ addTaskCallback?: (task: TaskDescriptor) => Promise<void>;
13
+ editTaskCallback?: (task: TaskDescriptor) => Promise<void>;
14
+ handleNavigateToWGs?: (value: HomeBlogPost | number) => Promise<void>;
15
+ handleNavigateToDossiers?: (value: HomeBlogPost | number) => Promise<void>;
8
16
  }
9
17
  /**
10
18
  * Sezione condivisa tra TMCopyToFolderForm e TMMergeToPdfForm
@@ -1,21 +1,28 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useCallback, useRef, useState } from 'react';
3
3
  import TreeView from 'devextreme-react/tree-view';
4
+ import { LayoutModes } from '@topconsultnpm/sdk-ts';
4
5
  import { SDKUI_Localizator } from '../../../helper';
5
6
  import { TMColors } from '../../../utils/theme';
6
7
  import { TMSplitterLayout } from '../../base/TMLayout';
7
8
  import TMRelationViewer from './TMRelationViewer';
8
- import { dedupeByTidDid, getDcmtKey, getFloatingLabelStyle, SPLITTER_MIN, SPLITTER_START_65_35, } from './copyAndMergeDcmtsShared';
9
+ import TMDcmtForm from './TMDcmtForm';
10
+ import { dedupeByTidDid, getDcmtKey, getFloatingLabelStyle, SPLITTER_MIN, SPLITTER_START_75_25, } from './copyAndMergeDcmtsShared';
9
11
  /**
10
12
  * Sezione condivisa tra TMCopyToFolderForm e TMMergeToPdfForm
11
13
  * che mostra l'elenco dei documenti correlati e il tree di selezione
12
14
  * per tipo documento / "solo metadati".
13
15
  */
14
- const TMDownloadRelationViewerSection = ({ selectedDcmtInfos, onSelectionChanged, }) => {
16
+ const TMDownloadRelationViewerSection = ({ selectedDcmtInfos, onSelectionChanged, allTasks, getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers }) => {
15
17
  const [focusedItem, setFocusedItem] = useState(null);
16
18
  const [selectedItems, setSelectedItems] = useState([]);
17
19
  const [allItems, setAllItems] = useState([]);
18
20
  const didInitSelectionRef = useRef(false);
21
+ // State for TMDcmtForm modal
22
+ const [isOpenDcmtForm, setIsOpenDcmtForm] = useState(false);
23
+ const [dcmtFormTID, setDcmtFormTID] = useState(undefined);
24
+ const [dcmtFormDID, setDcmtFormDID] = useState(undefined);
25
+ const [dcmtFormTitle, setDcmtFormTitle] = useState('');
19
26
  const updateSelection = useCallback((items) => {
20
27
  const deduped = dedupeByTidDid(items);
21
28
  setSelectedItems(deduped);
@@ -34,122 +41,133 @@ const TMDownloadRelationViewerSection = ({ selectedDcmtInfos, onSelectionChanged
34
41
  updateSelection(items.filter(i => i.isDcmt));
35
42
  }
36
43
  }, [updateSelection]);
37
- return (_jsx("div", { style: {
44
+ const handleDocumentDoubleClick = useCallback((tid, did, name) => {
45
+ setDcmtFormTID(tid);
46
+ setDcmtFormDID(did);
47
+ setDcmtFormTitle(name ?? '');
48
+ setIsOpenDcmtForm(true);
49
+ }, []);
50
+ return (_jsxs("div", { style: {
38
51
  position: 'relative',
39
52
  height: '100%',
40
53
  minHeight: 0,
41
54
  display: 'flex',
42
55
  flexDirection: 'column',
43
56
  boxSizing: 'border-box'
44
- }, children: _jsx("div", { style: { flex: 1, minHeight: 0, overflow: 'visible', paddingTop: '10px' }, children: _jsxs(TMSplitterLayout, { direction: 'horizontal', showSeparator: true, separatorSize: 8, separatorColor: 'transparent', separatorActiveColor: 'transparent', overflow: 'visible', min: SPLITTER_MIN, start: SPLITTER_START_65_35, children: [_jsxs("div", { style: {
45
- position: 'relative',
46
- height: '100%',
47
- minHeight: 0,
48
- overflow: 'visible',
49
- border: `1px solid ${TMColors.border_normal}`,
50
- borderRadius: '8px',
51
- padding: '4px 2px 2px 2px',
52
- backgroundColor: '#fff',
53
- boxSizing: 'border-box',
54
- display: 'flex',
55
- flexDirection: 'column'
56
- }, children: [_jsxs("span", { style: getFloatingLabelStyle(), title: `Documenti correlati (${SDKUI_Localizator.Selected}: ${selectedItems.filter(item => item.isDcmt).length})`, children: ["Documenti correlati (", SDKUI_Localizator.Selected, ": ", selectedItems.filter(item => item.isDcmt).length, ")"] }), _jsx("div", { style: { flex: 1, minHeight: 0, overflowX: 'auto', overflowY: 'auto' }, children: _jsx("div", { style: { minWidth: 'max-content', height: '100%' }, children: _jsx(TMRelationViewer, { inputDcmts: selectedDcmtInfos, isForMaster: false, defaultExpandAll: true, showMetadataNames: true, allowMultipleSelection: true, showExpandAllButton: true, focusedItem: focusedItem, selectedItems: selectedItems, onFocusedItemChanged: handleFocusedItemChanged, onSelectedItemsChanged: handleSelectedItemsChanged, onAllItemsChanged: handleAllItemsChanged }) }) })] }), _jsxs("div", { style: {
57
- position: 'relative',
58
- height: '100%',
59
- minHeight: 0,
60
- overflow: 'visible',
61
- border: `1px solid ${TMColors.border_normal}`,
62
- borderRadius: '8px',
63
- padding: '4px 2px 2px 2px',
64
- backgroundColor: '#fff',
65
- boxSizing: 'border-box',
66
- display: 'flex',
67
- flexDirection: 'column'
68
- }, children: [_jsx("span", { style: getFloatingLabelStyle(), title: "Tipo documento o vista", children: "Tipo documento o vista" }), _jsx("div", { style: { flex: 1, minHeight: 0, overflow: 'auto', padding: '8px', display: 'flex', flexDirection: 'column', gap: '6px' }, children: (() => {
69
- const dcmtItems = dedupeByTidDid(allItems.filter(item => item.isDcmt));
70
- const metadataOnlyItems = dcmtItems.filter(item => item.fileExt === null || item.fileExt === undefined);
71
- const totalDcmts = dcmtItems.length;
72
- const totalMetadataOnly = metadataOnlyItems.length;
73
- const selectedDcmtsList = selectedItems.filter(item => item.isDcmt);
74
- const selectedDcmts = selectedDcmtsList.length;
75
- const allSelected = totalDcmts > 0 && selectedDcmts === totalDcmts;
76
- const selectedMetadataOnlyCount = selectedDcmtsList.filter(item => item.fileExt === null || item.fileExt === undefined).length;
77
- const allMetadataOnlySelected = totalMetadataOnly > 0 && selectedMetadataOnlyCount === totalMetadataOnly;
78
- // Raggruppa per nome del DcmtTypeDescriptor (campo dtd.name)
79
- const getDtdName = (item) => item.dtd?.name ?? undefined;
80
- const dtdGroups = new Map();
81
- for (const item of dcmtItems) {
82
- const name = getDtdName(item);
83
- if (!name)
84
- continue;
85
- const arr = dtdGroups.get(name);
86
- if (arr)
87
- arr.push(item);
88
- else
89
- dtdGroups.set(name, [item]);
90
- }
91
- const sortedDtdNames = Array.from(dtdGroups.keys()).sort((a, b) => a.localeCompare(b));
92
- const selectedKeysSet = new Set(selectedDcmtsList.map(getDcmtKey));
93
- const dtdGroupInfos = sortedDtdNames.map((name) => {
94
- const items = dtdGroups.get(name) ?? [];
95
- const selectedCount = items.filter(it => selectedKeysSet.has(getDcmtKey(it))).length;
96
- return {
97
- name,
98
- items,
99
- total: items.length,
100
- allSelected: items.length > 0 && selectedCount === items.length,
101
- };
102
- });
103
- const treeItems = [
104
- {
105
- id: 'all',
106
- text: `Seleziona tutti (${totalDcmts})`,
107
- expanded: true,
108
- selected: allSelected,
109
- items: [
110
- ...dtdGroupInfos.map((g) => ({
111
- id: `dtd::${g.name}`,
112
- text: `${g.name} (${g.total})`,
113
- selected: g.allSelected,
114
- })),
115
- {
116
- id: 'metadataOnly',
117
- text: `Documenti di soli metadati (${totalMetadataOnly})`,
118
- selected: allMetadataOnlySelected,
119
- },
120
- ]
121
- }
122
- ];
123
- const handleItemSelectionChanged = (e) => {
124
- const itemData = e.itemData;
125
- if (!itemData)
126
- return;
127
- if (itemData.id === 'all') {
128
- updateSelection(itemData.selected ? dcmtItems : []);
57
+ }, children: [_jsx("div", { style: { flex: 1, minHeight: 0, overflow: 'visible', paddingTop: '10px' }, children: _jsxs(TMSplitterLayout, { direction: 'horizontal', showSeparator: true, separatorSize: 8, separatorColor: 'transparent', separatorActiveColor: 'transparent', overflow: 'visible', min: SPLITTER_MIN, start: SPLITTER_START_75_25, children: [_jsxs("div", { style: {
58
+ position: 'relative',
59
+ height: '100%',
60
+ minHeight: 0,
61
+ overflow: 'visible',
62
+ border: `1px solid ${TMColors.border_normal}`,
63
+ borderRadius: '8px',
64
+ padding: '4px 2px 2px 2px',
65
+ backgroundColor: '#fff',
66
+ boxSizing: 'border-box',
67
+ display: 'flex',
68
+ flexDirection: 'column'
69
+ }, children: [_jsxs("span", { style: getFloatingLabelStyle(), title: `Documenti correlati (${SDKUI_Localizator.Selected}: ${selectedItems.filter(item => item.isDcmt).length})`, children: ["Documenti correlati (", SDKUI_Localizator.Selected, ": ", selectedItems.filter(item => item.isDcmt).length, ")"] }), _jsx("div", { style: { flex: 1, minHeight: 0, overflowX: 'auto', overflowY: 'auto' }, children: _jsx("div", { style: { minWidth: 'max-content', height: '100%' }, children: _jsx(TMRelationViewer, { inputDcmts: selectedDcmtInfos, isForMaster: false, defaultExpandAll: true, showMetadataNames: true, allowMultipleSelection: true, showExpandAllButton: true, focusedItem: focusedItem, selectedItems: selectedItems, onFocusedItemChanged: handleFocusedItemChanged, onSelectedItemsChanged: handleSelectedItemsChanged, onAllItemsChanged: handleAllItemsChanged, onDocumentDoubleClick: handleDocumentDoubleClick }) }) })] }), _jsxs("div", { style: {
70
+ position: 'relative',
71
+ height: '100%',
72
+ minHeight: 0,
73
+ overflow: 'visible',
74
+ border: `1px solid ${TMColors.border_normal}`,
75
+ borderRadius: '8px',
76
+ padding: '4px 2px 2px 2px',
77
+ backgroundColor: '#fff',
78
+ boxSizing: 'border-box',
79
+ display: 'flex',
80
+ flexDirection: 'column'
81
+ }, children: [_jsx("span", { style: getFloatingLabelStyle(), title: "Tipo documento o vista", children: "Tipo documento o vista" }), _jsx("div", { style: { flex: 1, minHeight: 0, overflow: 'auto', padding: '8px', display: 'flex', flexDirection: 'column', gap: '6px' }, children: (() => {
82
+ const dcmtItems = dedupeByTidDid(allItems.filter(item => item.isDcmt));
83
+ const metadataOnlyItems = dcmtItems.filter(item => item.fileExt === null || item.fileExt === undefined);
84
+ const totalDcmts = dcmtItems.length;
85
+ const totalMetadataOnly = metadataOnlyItems.length;
86
+ const selectedDcmtsList = selectedItems.filter(item => item.isDcmt);
87
+ const selectedDcmts = selectedDcmtsList.length;
88
+ const allSelected = totalDcmts > 0 && selectedDcmts === totalDcmts;
89
+ const selectedMetadataOnlyCount = selectedDcmtsList.filter(item => item.fileExt === null || item.fileExt === undefined).length;
90
+ const allMetadataOnlySelected = totalMetadataOnly > 0 && selectedMetadataOnlyCount === totalMetadataOnly;
91
+ // Raggruppa per nome del DcmtTypeDescriptor (campo dtd.name)
92
+ const getDtdName = (item) => item.dtd?.name ?? undefined;
93
+ const dtdGroups = new Map();
94
+ for (const item of dcmtItems) {
95
+ const name = getDtdName(item);
96
+ if (!name)
97
+ continue;
98
+ const arr = dtdGroups.get(name);
99
+ if (arr)
100
+ arr.push(item);
101
+ else
102
+ dtdGroups.set(name, [item]);
129
103
  }
130
- else if (itemData.id === 'metadataOnly') {
131
- if (itemData.selected) {
132
- updateSelection([...selectedItems, ...metadataOnlyItems]);
104
+ const sortedDtdNames = Array.from(dtdGroups.keys()).sort((a, b) => a.localeCompare(b));
105
+ const selectedKeysSet = new Set(selectedDcmtsList.map(getDcmtKey));
106
+ const dtdGroupInfos = sortedDtdNames.map((name) => {
107
+ const items = dtdGroups.get(name) ?? [];
108
+ const selectedCount = items.filter(it => selectedKeysSet.has(getDcmtKey(it))).length;
109
+ return {
110
+ name,
111
+ items,
112
+ total: items.length,
113
+ allSelected: items.length > 0 && selectedCount === items.length,
114
+ };
115
+ });
116
+ const treeItems = [
117
+ {
118
+ id: 'all',
119
+ text: `Seleziona tutti (${totalDcmts})`,
120
+ expanded: true,
121
+ selected: allSelected,
122
+ items: [
123
+ ...dtdGroupInfos.map((g) => ({
124
+ id: `dtd::${g.name}`,
125
+ text: `${g.name} (${g.total})`,
126
+ selected: g.allSelected,
127
+ })),
128
+ {
129
+ id: 'metadataOnly',
130
+ text: `Documenti di soli metadati (${totalMetadataOnly})`,
131
+ selected: allMetadataOnlySelected,
132
+ },
133
+ ]
133
134
  }
134
- else {
135
- const metadataKeys = new Set(metadataOnlyItems.map(getDcmtKey));
136
- updateSelection(selectedItems.filter(item => !metadataKeys.has(getDcmtKey(item))));
135
+ ];
136
+ const handleItemSelectionChanged = (e) => {
137
+ const itemData = e.itemData;
138
+ if (!itemData)
139
+ return;
140
+ if (itemData.id === 'all') {
141
+ updateSelection(itemData.selected ? dcmtItems : []);
137
142
  }
138
- }
139
- else if (typeof itemData.id === 'string' && itemData.id.startsWith('dtd::')) {
140
- const dtdName = itemData.id.substring('dtd::'.length);
141
- const groupItems = dtdGroups.get(dtdName) ?? [];
142
- if (itemData.selected) {
143
- updateSelection([...selectedItems, ...groupItems]);
143
+ else if (itemData.id === 'metadataOnly') {
144
+ if (itemData.selected) {
145
+ updateSelection([...selectedItems, ...metadataOnlyItems]);
146
+ }
147
+ else {
148
+ const metadataKeys = new Set(metadataOnlyItems.map(getDcmtKey));
149
+ updateSelection(selectedItems.filter(item => !metadataKeys.has(getDcmtKey(item))));
150
+ }
144
151
  }
145
- else {
146
- const groupKeys = new Set(groupItems.map(getDcmtKey));
147
- updateSelection(selectedItems.filter(item => !groupKeys.has(getDcmtKey(item))));
152
+ else if (typeof itemData.id === 'string' && itemData.id.startsWith('dtd::')) {
153
+ const dtdName = itemData.id.substring('dtd::'.length);
154
+ const groupItems = dtdGroups.get(dtdName) ?? [];
155
+ if (itemData.selected) {
156
+ updateSelection([...selectedItems, ...groupItems]);
157
+ }
158
+ else {
159
+ const groupKeys = new Set(groupItems.map(getDcmtKey));
160
+ updateSelection(selectedItems.filter(item => !groupKeys.has(getDcmtKey(item))));
161
+ }
148
162
  }
149
- }
150
- };
151
- const dtdSignature = dtdGroupInfos.map(g => `${g.name}:${g.total}:${g.allSelected ? 1 : 0}`).join('|');
152
- return (_jsx("div", { style: { minWidth: '280px', width: 'max-content', flexShrink: 0 }, children: _jsx(TreeView, { items: treeItems, showCheckBoxesMode: 'normal', selectionMode: 'multiple', selectNodesRecursive: false, selectByClick: true, onItemSelectionChanged: handleItemSelectionChanged }, `tv-${allSelected}-${allMetadataOnlySelected}-${totalDcmts}-${totalMetadataOnly}-${dtdSignature}`) }));
153
- })() })] })] }, "TMDocumentDownload-relation-horizontal") }) }));
163
+ };
164
+ const dtdSignature = dtdGroupInfos.map(g => `${g.name}:${g.total}:${g.allSelected ? 1 : 0}`).join('|');
165
+ return (_jsx("div", { style: { minWidth: '280px', width: 'max-content', flexShrink: 0 }, children: _jsx(TreeView, { items: treeItems, showCheckBoxesMode: 'normal', selectionMode: 'multiple', selectNodesRecursive: false, selectByClick: true, onItemSelectionChanged: handleItemSelectionChanged }, `tv-${allSelected}-${allMetadataOnlySelected}-${totalDcmts}-${totalMetadataOnly}-${dtdSignature}`) }));
166
+ })() })] })] }, "TMDocumentDownload-relation-horizontal") }), isOpenDcmtForm && dcmtFormTID !== undefined && dcmtFormDID !== undefined && (_jsx(TMDcmtForm, { isModal: true, titleModal: dcmtFormTitle, TID: dcmtFormTID, DID: dcmtFormDID, layoutMode: LayoutModes.Update, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, onClose: () => {
167
+ setIsOpenDcmtForm(false);
168
+ setDcmtFormTID(undefined);
169
+ setDcmtFormDID(undefined);
170
+ setDcmtFormTitle('');
171
+ } }))] }));
154
172
  };
155
173
  export default TMDownloadRelationViewerSection;
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { DcmtInfo } from '../../../ts';
3
3
  import { MergePdfManagerType } from '../../../helper';
4
+ import { HomeBlogPost, TaskDescriptor } from '@topconsultnpm/sdk-ts';
4
5
  import { TMCopyToFolderMode } from '../../../hooks/useDocumentOperations';
5
6
  interface ITMMergeToPdfFormProps {
6
7
  mode: TMCopyToFolderMode;
@@ -8,6 +9,13 @@ interface ITMMergeToPdfFormProps {
8
9
  onClose: () => void;
9
10
  showTMRelationViewer: boolean;
10
11
  mergePdfManager?: MergePdfManagerType;
12
+ allTasks?: Array<TaskDescriptor>;
13
+ getAllTasks?: () => Promise<void>;
14
+ deleteTaskByIdsCallback?: (deletedTaskIds: Array<number>) => Promise<void>;
15
+ addTaskCallback?: (task: TaskDescriptor) => Promise<void>;
16
+ editTaskCallback?: (task: TaskDescriptor) => Promise<void>;
17
+ handleNavigateToWGs?: (value: HomeBlogPost | number) => Promise<void>;
18
+ handleNavigateToDossiers?: (value: HomeBlogPost | number) => Promise<void>;
11
19
  }
12
20
  /**
13
21
  * Form per l'unione di più documenti PDF in un singolo file.
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from 'react';
2
+ import { useRef, useState } from 'react';
3
3
  import { DownloadTypes } from '../../../ts';
4
- import { calcResponsiveSizes, IconPlay, SDKUI_Globals, SDKUI_Localizator, } from '../../../helper';
5
- import { DcmtOpers, GeneralRetrieveFormats, ResultTypes, RetrieveFileOptions, ValidationItem, } from '@topconsultnpm/sdk-ts';
4
+ import { calcResponsiveSizes, IconFolderOpen, IconPlay, IconUndo, SDKUI_Globals, SDKUI_Localizator, } from '../../../helper';
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';
8
8
  import TMTextBox from '../../editors/TMTextBox';
@@ -13,22 +13,56 @@ import { TMLayoutWaitingContainer } from '../../base/TMWaitPanel';
13
13
  import { TMSplitterLayout } from '../../base/TMLayout';
14
14
  import { TMColors } from '../../../utils/theme';
15
15
  import TMDownloadRelationViewerSection from './TMDownloadRelationViewerSection';
16
- import { getDcmtInfosToDownload, getFloatingLabelStyle, isPdfExt, MIN_PDF_FOR_MERGE, SPLITTER_MIN, SPLITTER_START_65_35, } from './copyAndMergeDcmtsShared';
16
+ import { getDcmtInfosToDownload, getFloatingLabelStyle, isDirectoryPickerSupported, isPdfExt, MIN_PDF_FOR_MERGE, SPLITTER_MIN, SPLITTER_START_70_30, } from './copyAndMergeDcmtsShared';
17
+ import ShowAlert from '../../base/TMAlert';
17
18
  /**
18
19
  * Form per l'unione di più documenti PDF in un singolo file.
19
20
  * Condivide TMDownloadRelationViewerSection e gli helper in copyAndMergeDcmtsShared
20
21
  * con TMCopyToFolderForm.
21
22
  */
22
- const TMMergeToPdfForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationViewer, mergePdfManager }) => {
23
+ const TMMergeToPdfForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationViewer, mergePdfManager, allTasks, getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers }) => {
23
24
  const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, } = useDcmtOperations();
24
25
  const deviceType = useDeviceType();
25
- const [pdfFileName, setPdfFileName] = useState('');
26
+ const [pdfFileName, setPdfFileName] = useState('merged.pdf');
27
+ const [destinationFolder, setDestinationFolder] = useState('Download');
26
28
  const [selectedItemsRelationViewer, setSelectedItemsRelationViewer] = useState([]);
29
+ // ---- Ref per la selezione cartella (File System Access API) ----
30
+ const folderHandleRef = useRef(null);
31
+ const skipSelectFolderRef = useRef(false);
32
+ const isPickerActiveRef = useRef(false);
33
+ const isUsingDefaultDownloads = destinationFolder === 'Download' && !folderHandleRef.current;
34
+ // ---- Handler dei campi cartella ----
35
+ const handleFolderValueChange = (e) => {
36
+ setDestinationFolder(e.target.value);
37
+ folderHandleRef.current = null;
38
+ };
39
+ const handleSelectFolder = async () => {
40
+ if (skipSelectFolderRef.current) {
41
+ skipSelectFolderRef.current = false;
42
+ return;
43
+ }
44
+ if (isPickerActiveRef.current)
45
+ return;
46
+ try {
47
+ isPickerActiveRef.current = true;
48
+ const dirHandle = await window.showDirectoryPicker({ mode: 'readwrite' });
49
+ folderHandleRef.current = dirHandle;
50
+ setDestinationFolder(dirHandle.name);
51
+ }
52
+ catch (err) {
53
+ if (err.name !== 'AbortError') {
54
+ console.error('Errore nella selezione della cartella:', err);
55
+ }
56
+ }
57
+ finally {
58
+ isPickerActiveRef.current = false;
59
+ }
60
+ };
27
61
  const getTitle = () => {
28
62
  const count = ` (${selectedDcmtInfos.length})`;
29
63
  const modeLabelMap = {
30
- onlySelected: 'Solo i documenti selezionati',
31
- customized: 'Documenti di primo livello e i correlati selezionati',
64
+ onlySelected: 'Documenti selezionati',
65
+ customized: 'Documenti selezionati e i correlati',
32
66
  };
33
67
  const modeLabel = modeLabelMap[mode] || modeLabelMap.onlySelected;
34
68
  return `Unisci in un file PDF - ${modeLabel}${count}`;
@@ -38,25 +72,51 @@ const TMMergeToPdfForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationView
38
72
  if (!pdfFileName.trim()) {
39
73
  pdfValidationItems.push(new ValidationItem(ResultTypes.ERROR, 'Nome file PDF', SDKUI_Localizator.RequiredField));
40
74
  }
41
- // ---- Statistiche selezione PDF / non-PDF ----
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
+ // ---- Statistiche selezione PDF / convertibili / non-PDF ----
90
+ const convertibleSelectedItems = (() => {
91
+ if (showTMRelationViewer) {
92
+ return selectedItemsRelationViewer
93
+ .filter(i => i.isDcmt && isConvertibleToPdfExt(i.fileExt))
94
+ .map(i => ({ key: `${i.tid}_${i.did}`, ext: i.fileExt ?? undefined }));
95
+ }
96
+ return selectedDcmtInfos
97
+ .filter(d => isConvertibleToPdfExt(d.FILEEXT))
98
+ .map(d => ({ key: `${d.TID}_${d.DID}`, ext: d.FILEEXT }));
99
+ })();
100
+ const hasConvertibleSelected = convertibleSelectedItems.length > 0;
42
101
  const nonPdfSelectedItems = (() => {
43
102
  if (showTMRelationViewer) {
44
103
  return selectedItemsRelationViewer
45
- .filter(i => i.isDcmt && !isPdfExt(i.fileExt))
104
+ .filter(i => i.isDcmt && !isPdfExt(i.fileExt) && !isConvertibleToPdfExt(i.fileExt))
46
105
  .map(i => ({ key: `${i.tid}_${i.did}`, ext: i.fileExt ?? undefined }));
47
106
  }
48
107
  return selectedDcmtInfos
49
- .filter(d => !isPdfExt(d.FILEEXT))
108
+ .filter(d => !isPdfExt(d.FILEEXT) && !isConvertibleToPdfExt(d.FILEEXT))
50
109
  .map(d => ({ key: `${d.TID}_${d.DID}`, ext: d.FILEEXT }));
51
110
  })();
52
111
  const hasNonPdfSelected = nonPdfSelectedItems.length > 0;
53
- const pdfSelectedCount = (() => {
112
+ // Conteggio file unibili: PDF nativi + file convertibili
113
+ const mergeableSelectedCount = (() => {
54
114
  if (showTMRelationViewer) {
55
- return selectedItemsRelationViewer.filter(i => i.isDcmt && isPdfExt(i.fileExt)).length;
115
+ return selectedItemsRelationViewer.filter(i => i.isDcmt && (isPdfExt(i.fileExt) || isConvertibleToPdfExt(i.fileExt))).length;
56
116
  }
57
- return selectedDcmtInfos.filter(d => isPdfExt(d.FILEEXT)).length;
117
+ return selectedDcmtInfos.filter(d => isPdfExt(d.FILEEXT) || isConvertibleToPdfExt(d.FILEEXT)).length;
58
118
  })();
59
- const hasEnoughPdfForMerge = pdfSelectedCount >= MIN_PDF_FOR_MERGE;
119
+ const hasEnoughPdfForMerge = mergeableSelectedCount >= MIN_PDF_FOR_MERGE;
60
120
  const isFormValid = () => pdfValidationItems.length === 0;
61
121
  // ---- Recupero dei file PDF da unire (condiviso tra Esegui e Anteprima) ----
62
122
  const collectPdfFilesToMerge = async () => {
@@ -69,28 +129,29 @@ const TMMergeToPdfForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationView
69
129
  const pdfDcmtInfosToDownload = dcmtInfosToDownload.filter(d => !nonPdfKeys.has(`${d.TID}_${d.DID}`));
70
130
  if (pdfDcmtInfosToDownload.length === 0) {
71
131
  TMMessageBoxManager.show({
72
- message: 'Tra i documenti selezionati non è presente alcun file PDF: l\'unione non può essere eseguita.',
132
+ message: 'Tra i documenti selezionati non è presente alcun file PDF o convertibile in PDF: l\'unione non può essere eseguita.',
73
133
  buttons: [ButtonNames.OK]
74
134
  });
75
135
  return null;
76
136
  }
77
137
  if (pdfDcmtInfosToDownload.length < MIN_PDF_FOR_MERGE) {
78
138
  TMMessageBoxManager.show({
79
- message: `Tra i documenti selezionati è presente un solo file PDF: per l'unione ne servono almeno ${MIN_PDF_FOR_MERGE}.`,
139
+ message: `Tra i documenti selezionati è presente un solo file PDF o convertibile: per l'unione ne servono almeno ${MIN_PDF_FOR_MERGE}.`,
80
140
  buttons: [ButtonNames.OK]
81
141
  });
82
142
  return null;
83
143
  }
84
144
  const pdfFiles = [];
85
- const retrieveOptions = new RetrieveFileOptions();
86
- retrieveOptions.retrieveReason = DcmtOpers.None;
87
- retrieveOptions.generalRetrieveFormat = GeneralRetrieveFormats.Original;
88
- retrieveOptions.invoiceRetrieveFormat = SDKUI_Globals.userSettings.searchSettings.invoiceRetrieveFormat;
89
- retrieveOptions.orderRetrieveFormat = SDKUI_Globals.userSettings.searchSettings.orderRetrieveFormat;
145
+ const rfo = new RetrieveFileOptions();
146
+ rfo.retrieveReason = DcmtOpers.None;
147
+ rfo.generalRetrieveFormat = GeneralRetrieveFormats.Original;
148
+ rfo.cvtFormat = FileFormats.PDF;
149
+ rfo.invoiceRetrieveFormat = SDKUI_Globals.userSettings?.searchSettings.invoiceRetrieveFormat;
150
+ rfo.orderRetrieveFormat = SDKUI_Globals.userSettings?.searchSettings.orderRetrieveFormat;
90
151
  const collectFileForMerge = async (file, _dcmtInfo) => {
91
152
  pdfFiles.push(file);
92
153
  };
93
- await downloadDcmtsAsync(pdfDcmtInfosToDownload, DownloadTypes.Dcmt, 'download', collectFileForMerge, undefined, true, retrieveOptions, false);
154
+ await downloadDcmtsAsync(pdfDcmtInfosToDownload, DownloadTypes.Dcmt, 'download', collectFileForMerge, undefined, true, rfo, false);
94
155
  if (pdfFiles.length === 0) {
95
156
  TMMessageBoxManager.show({ message: 'Nessun file disponibile per l\'unione.', buttons: [ButtonNames.OK] });
96
157
  return null;
@@ -110,15 +171,26 @@ const TMMergeToPdfForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationView
110
171
  const pdfFiles = await collectPdfFilesToMerge();
111
172
  if (!pdfFiles)
112
173
  return;
113
- const finalName = pdfFileName.trim().toLowerCase().endsWith('.pdf')
114
- ? pdfFileName.trim()
115
- : pdfFileName.trim() + '.pdf';
174
+ const finalName = pdfFileName.trim().toLowerCase().endsWith('.pdf') ? pdfFileName.trim() : pdfFileName.trim() + '.pdf';
116
175
  try {
117
- await mergePdfManager.mergeAndDownload(pdfFiles, finalName);
176
+ // Se c'è una cartella selezionata (non Download di default), salva direttamente nella cartella
177
+ if (folderHandleRef.current) {
178
+ const mergedFile = await mergePdfManager.mergeToFile(pdfFiles, finalName);
179
+ const fileHandle = await folderHandleRef.current.getFileHandle(finalName, { create: true });
180
+ const writable = await fileHandle.createWritable();
181
+ await writable.write(mergedFile);
182
+ await writable.close();
183
+ ShowAlert({ message: `Il file PDF unito è stato salvato nella cartella "${folderHandleRef.current.name}".`, mode: 'success', duration: 3000, title: 'Successo' });
184
+ }
185
+ else {
186
+ // Altrimenti usa il download standard del browser
187
+ await mergePdfManager.mergeAndDownload(pdfFiles, finalName);
188
+ ShowAlert({ message: 'Il file PDF unito è stato scaricato.', mode: 'success', duration: 3000, title: 'Successo' });
189
+ }
118
190
  }
119
191
  catch (err) {
120
- console.error('Errore durante l\'unione dei PDF:', err);
121
- TMMessageBoxManager.show({ message: 'Errore durante l\'unione dei PDF.', buttons: [ButtonNames.OK] });
192
+ console.error('Errore durante l\'unione dei file PDF o convertibili:', err);
193
+ TMMessageBoxManager.show({ message: 'Errore durante l\'unione dei file PDF o convertibili.', buttons: [ButtonNames.OK] });
122
194
  return;
123
195
  }
124
196
  onClose();
@@ -136,7 +208,47 @@ const TMMergeToPdfForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationView
136
208
  display: 'flex',
137
209
  flexDirection: 'column',
138
210
  boxSizing: 'border-box'
139
- }, children: [_jsx("span", { style: getFloatingLabelStyle(), title: "Parametri di configurazione (Unisci in PDF)", children: "Parametri di configurazione" }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '12px', overflowY: 'auto', flex: 1 }, children: [_jsx(TMTextBox, { label: "Nome file PDF", value: pdfFileName, validationItems: pdfValidationItems, autoComplete: "one-time-code", placeHolder: "merged.pdf", onValueChanged: (e) => setPdfFileName(e.target.value) }), (!hasEnoughPdfForMerge || hasNonPdfSelected) && (_jsxs("div", { style: {
211
+ }, children: [_jsx("span", { style: getFloatingLabelStyle(), title: "Parametri di configurazione (Unisci in PDF)", children: "Parametri di configurazione" }), _jsxs("div", { style: {
212
+ display: 'flex',
213
+ flexDirection: 'column',
214
+ gap: '12px',
215
+ flex: 1,
216
+ overflowY: 'auto',
217
+ minHeight: 0,
218
+ }, children: [_jsxs("div", { style: { display: 'grid', gridTemplateColumns: isDirectoryPickerSupported() ? '1fr 1fr' : '1fr', gap: '12px' }, children: [isDirectoryPickerSupported() && (_jsx(TMTextBox, { label: "Percorso", value: destinationFolder, onValueChanged: handleFolderValueChange, readOnly: true, placeHolder: "Download", onClick: handleSelectFolder, buttons: [
219
+ {
220
+ icon: _jsx(IconFolderOpen, {}),
221
+ text: 'Seleziona cartella',
222
+ onClick: handleSelectFolder
223
+ },
224
+ ...(!isUsingDefaultDownloads ? [{
225
+ icon: _jsx(IconUndo, {}),
226
+ text: 'Ripristina Download',
227
+ onClick: () => {
228
+ skipSelectFolderRef.current = true;
229
+ setDestinationFolder('Download');
230
+ folderHandleRef.current = null;
231
+ }
232
+ }] : [])
233
+ ] })), _jsx(TMTextBox, { label: "Nome file PDF", value: pdfFileName, validationItems: pdfValidationItems, autoComplete: "one-time-code", onValueChanged: (e) => setPdfFileName(e.target.value) })] }), hasConvertibleSelected && (_jsxs("div", { style: {
234
+ display: 'flex',
235
+ flexDirection: 'column',
236
+ gap: '6px',
237
+ padding: '8px 12px',
238
+ border: '1px solid #6db3f0',
239
+ borderRadius: '5px',
240
+ backgroundColor: '#e2f0fd',
241
+ color: '#00527a',
242
+ fontSize: '0.85rem'
243
+ }, children: [_jsx("strong", { children: "Nota" }), _jsx("ul", { style: { margin: 0, paddingLeft: '18px', display: 'flex', flexDirection: 'column', gap: '4px' }, children: _jsx("li", { children: (() => {
244
+ const extSet = Array.from(new Set(convertibleSelectedItems.map(i => (i.ext ?? '').toString().trim().toLowerCase().replace(/^\./, '')).filter(e => e.length > 0)));
245
+ const extLabel = extSet.length > 0
246
+ ? ` (${extSet.map(e => '.' + e).join(', ')})`
247
+ : '';
248
+ return convertibleSelectedItems.length === 1
249
+ ? `Un documento${extLabel} verrà convertito in PDF durante l'unione.`
250
+ : `${convertibleSelectedItems.length} documenti${extLabel} verranno convertiti in PDF durante l'unione.`;
251
+ })() }) })] })), (!hasEnoughPdfForMerge || hasNonPdfSelected || !isDirectoryPickerSupported()) && (_jsxs("div", { style: {
140
252
  display: 'flex',
141
253
  flexDirection: 'column',
142
254
  gap: '6px',
@@ -146,9 +258,9 @@ const TMMergeToPdfForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationView
146
258
  backgroundColor: '#fdf5e2',
147
259
  color: '#7a5d00',
148
260
  fontSize: '0.85rem'
149
- }, children: [_jsx("strong", { children: "Attenzione" }), _jsxs("ul", { style: { margin: 0, paddingLeft: '18px', display: 'flex', flexDirection: 'column', gap: '4px' }, children: [!hasEnoughPdfForMerge && (_jsx("li", { children: pdfSelectedCount === 0
150
- ? `Nessun PDF tra i selezionati: ne servono almeno ${MIN_PDF_FOR_MERGE}.`
151
- : `Solo 1 PDF tra i selezionati: ne servono almeno ${MIN_PDF_FOR_MERGE}.` })), hasNonPdfSelected && (_jsx("li", { children: (() => {
261
+ }, children: [_jsx("strong", { children: "Attenzione" }), _jsxs("ul", { style: { margin: 0, paddingLeft: '18px', display: 'flex', flexDirection: 'column', gap: '4px' }, children: [!isDirectoryPickerSupported() && (_jsx("li", { children: "Il browser in uso non supporta la selezione della cartella. I file verranno scaricati nella cartella Download." })), !hasEnoughPdfForMerge && (_jsx("li", { children: mergeableSelectedCount === 0
262
+ ? `Nessun file PDF o convertibile tra i selezionati: ne servono almeno ${MIN_PDF_FOR_MERGE}.`
263
+ : `Solo 1 file PDF o convertibile tra i selezionati: ne servono almeno ${MIN_PDF_FOR_MERGE}.` })), hasNonPdfSelected && (_jsx("li", { children: (() => {
152
264
  const extSet = Array.from(new Set(nonPdfSelectedItems.map(i => (i.ext ?? '').toString().trim().toLowerCase().replace(/^\./, '')).filter(e => e.length > 0)));
153
265
  const extLabel = extSet.length > 0
154
266
  ? ` (${extSet.map(e => '.' + e).join(', ')})`
@@ -157,7 +269,7 @@ const TMMergeToPdfForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationView
157
269
  ? `Un documento non è in formato PDF${extLabel} e sarà escluso dall'unione.`
158
270
  : `${nonPdfSelectedItems.length} documenti non sono in formato PDF${extLabel} e saranno esclusi dall'unione.`;
159
271
  })() }))] })] }))] })] }));
160
- return (_jsx(TMModal, { width: calcResponsiveSizes(deviceType, showTMRelationViewer ? '90%' : '480px', showTMRelationViewer ? '90%' : '480px', '95%'), height: calcResponsiveSizes(deviceType, showTMRelationViewer ? '90%' : 'auto', showTMRelationViewer ? '90%' : 'auto', showTMRelationViewer ? '95%' : 'auto'), 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', gap: '16px', padding: '16px', 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: 'visible', min: SPLITTER_MIN, start: SPLITTER_START_65_35, children: [_jsx(TMDownloadRelationViewerSection, { selectedDcmtInfos: selectedDcmtInfos, onSelectionChanged: setSelectedItemsRelationViewer }), configSection] }, "TMMergeToPdf-relation-config") })) : (configSection), _jsx("div", { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', gap: '12px', flexShrink: 0 }, children: _jsx(TMButton, { caption: pdfSelectedCount === 0 ? 'Unisci in PDF' : `Unisci ${pdfSelectedCount} file in PDF`, icon: _jsx(IconPlay, {}), color: 'success', showTooltip: false, disabled: !isFormValid()
272
+ return (_jsx(TMModal, { width: calcResponsiveSizes(deviceType, showTMRelationViewer ? '90%' : '500px', showTMRelationViewer ? '90%' : '500px', '95%'), height: calcResponsiveSizes(deviceType, showTMRelationViewer ? '90%' : '500px', showTMRelationViewer ? '90%' : '500px', showTMRelationViewer ? '95%' : '500px'), 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', gap: '16px', padding: '16px', 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_70_30, children: [_jsx(TMDownloadRelationViewerSection, { selectedDcmtInfos: selectedDcmtInfos, onSelectionChanged: setSelectedItemsRelationViewer, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), configSection] }, "TMMergeToPdf-relation-config") })) : (configSection), _jsx("div", { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', gap: '12px', flexShrink: 0 }, children: _jsx(TMButton, { caption: mergeableSelectedCount === 0 ? 'Unisci in PDF' : `Unisci ${mergeableSelectedCount} file in PDF`, icon: _jsx(IconPlay, {}), color: 'success', showTooltip: false, disabled: !isFormValid()
161
273
  || (showTMRelationViewer && selectedItemsRelationViewer.filter(i => i.isDcmt).length === 0)
162
274
  || !hasEnoughPdfForMerge, onClick: run }) })] }) }) }));
163
275
  };
@@ -3,8 +3,9 @@ import { DcmtInfo } from '../../../ts';
3
3
  import { DocumentDownloadSettings, FileNamingMode } from '../../../helper';
4
4
  import { IRelatedDcmt } from './TMMasterDetailDcmts';
5
5
  export declare const SPLITTER_MIN: string[];
6
- export declare const SPLITTER_START_HALF: string[];
7
- export declare const SPLITTER_START_65_35: string[];
6
+ export declare const SPLITTER_START_60_40: string[];
7
+ export declare const SPLITTER_START_70_30: string[];
8
+ export declare const SPLITTER_START_75_25: string[];
8
9
  /** Numero minimo di file PDF necessari per poterli unire in un unico documento. */
9
10
  export declare const MIN_PDF_FOR_MERGE = 2;
10
11
  /** Stile per le etichette "floating" posizionate sopra i bordi dei container */
@@ -5,8 +5,9 @@ import { TMColors } from '../../../utils/theme';
5
5
  // Costanti condivise tra TMCopyToFolderForm e TMMergeToPdfForm
6
6
  // ============================================================
7
7
  export const SPLITTER_MIN = ['50', '50'];
8
- export const SPLITTER_START_HALF = ['50%', '50%'];
9
- export const SPLITTER_START_65_35 = ['65%', '35%'];
8
+ export const SPLITTER_START_60_40 = ['60%', '40%'];
9
+ export const SPLITTER_START_70_30 = ['70%', '30%'];
10
+ export const SPLITTER_START_75_25 = ['75%', '25%'];
10
11
  /** Numero minimo di file PDF necessari per poterli unire in un unico documento. */
11
12
  export const MIN_PDF_FOR_MERGE = 2;
12
13
  // ============================================================
@@ -1,7 +1,8 @@
1
- import { RetrieveFileOptions, DcmtOpers, FileDescriptor, GeneralRetrieveFormats, InvoiceRetrieveFormats, OrderRetrieveFormats } from '@topconsultnpm/sdk-ts';
1
+ import { RetrieveFileOptions, DcmtOpers, FileDescriptor, GeneralRetrieveFormats, InvoiceRetrieveFormats, OrderRetrieveFormats, FileFormats } from '@topconsultnpm/sdk-ts';
2
2
  import { DcmtInfo, DcmtOperationTypes, DownloadModes, DownloadTypes } from '../ts';
3
3
  export interface RetrieveFormatOptions {
4
4
  retrieveReason?: DcmtOpers;
5
+ cvtFormat?: FileFormats;
5
6
  generalRetrieveFormat?: GeneralRetrieveFormats;
6
7
  invoiceRetrieveFormat?: InvoiceRetrieveFormats;
7
8
  orderRetrieveFormat?: OrderRetrieveFormats;
@@ -73,6 +73,8 @@ export const useDcmtOperations = () => {
73
73
  abortController = new AbortController();
74
74
  const rfo = new RetrieveFileOptions();
75
75
  rfo.retrieveReason = retrieveOptions?.retrieveReason ?? DcmtOpers.ShowFile;
76
+ if (retrieveOptions?.cvtFormat !== undefined)
77
+ rfo.cvtFormat = retrieveOptions.cvtFormat;
76
78
  if (retrieveOptions?.generalRetrieveFormat !== undefined)
77
79
  rfo.generalRetrieveFormat = retrieveOptions.generalRetrieveFormat;
78
80
  rfo.invoiceRetrieveFormat = retrieveOptions?.invoiceRetrieveFormat ?? SDKUI_Globals.userSettings.searchSettings.invoiceRetrieveFormat;
@@ -710,7 +710,7 @@ export const useDocumentOperations = (props) => {
710
710
  {
711
711
  id: 'merge-pdf-only-selected',
712
712
  icon: _jsx("i", { className: "dx-icon-pdffile", style: { fontSize: '18px' } }),
713
- name: 'Solo i documenti selezionati',
713
+ name: 'I documenti selezionati',
714
714
  onClick: () => {
715
715
  setShowTMRelationViewerInCopyToFolderForm(false);
716
716
  setOpenCopyToFolderForm({ open: true, operationType: 'mergeToPdf', mode: 'onlySelected' });
@@ -719,7 +719,7 @@ export const useDocumentOperations = (props) => {
719
719
  {
720
720
  id: 'merge-pdf-customized',
721
721
  icon: _jsx("i", { className: "dx-icon-pdffile", style: { fontSize: '18px' } }),
722
- name: 'Documenti di primo livello e i correlati selezionati',
722
+ name: 'I documenti selezionati e i correlati',
723
723
  onClick: () => {
724
724
  setShowTMRelationViewerInCopyToFolderForm(true);
725
725
  setOpenCopyToFolderForm({ open: true, operationType: 'mergeToPdf', mode: 'customized' });
@@ -739,7 +739,7 @@ export const useDocumentOperations = (props) => {
739
739
  {
740
740
  id: 'copy-to-folder-only-selected',
741
741
  icon: _jsx(IconCopy, {}),
742
- name: 'Solo i documenti selezionati',
742
+ name: 'I documenti selezionati',
743
743
  onClick: () => {
744
744
  setShowTMRelationViewerInCopyToFolderForm(false);
745
745
  setOpenCopyToFolderForm({ open: true, operationType: 'copyToFolder', mode: 'onlySelected' });
@@ -748,7 +748,7 @@ export const useDocumentOperations = (props) => {
748
748
  {
749
749
  id: 'copy-to-folder-customized',
750
750
  icon: _jsx(IconCopy, {}),
751
- name: 'Documenti di primo livello e i correlati selezionati',
751
+ name: 'I documenti selezionati e i correlati',
752
752
  onClick: () => {
753
753
  setShowTMRelationViewerInCopyToFolderForm(true);
754
754
  setOpenCopyToFolderForm({ open: true, operationType: 'copyToFolder', mode: 'customized', });
@@ -1263,7 +1263,7 @@ export const useDocumentOperations = (props) => {
1263
1263
  updateBatchUpdateForm(false);
1264
1264
  setIsModifiedBatchUpdate(false);
1265
1265
  await onRefreshDataRowsAsync?.();
1266
- }, onStatusChanged: (isModified) => { setIsModifiedBatchUpdate(isModified); } }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: approvalVID ? selectedDcmtInfos.map(item => ({ ...item, TID: approvalVID })) : selectedDcmtInfos, isReject: 0, onClose: () => updateShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: approvalVID ? selectedDcmtInfos.map(item => ({ ...item, TID: approvalVID })) : selectedDcmtInfos, isReject: 1, onClose: () => updateShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: approvalVID ? selectedDcmtInfos.map(item => ({ ...item, TID: approvalVID })) : selectedDcmtInfos, onClose: () => updateShowReAssignPopup(false) }), showMoreInfoPopup && _jsx(WorkFlowMoreInfoPopUp, { fromDTD: dtd, TID: contextConfig.approvalTID, DID: focusedItem?.DID, deviceType: deviceType, onCompleted: handleWFOperationCompleted, onClose: () => updateShowMoreInfoPopup(false), allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, triggerBlogRefresh: onRefreshBlogDatagrid }), openCopyToFolderForm.open && openCopyToFolderForm.operationType === 'mergeToPdf' && _jsx(TMMergeToPdfForm, { mode: openCopyToFolderForm.mode, selectedDcmtInfos: selectedDcmtInfos, onClose: () => setOpenCopyToFolderForm({ open: false, operationType: 'copyToFolder', mode: 'onlySelected' }), showTMRelationViewer: showTMRelationViewerInCopyToFolderForm, mergePdfManager: mergePdfManager }), openCopyToFolderForm.open && openCopyToFolderForm.operationType === 'copyToFolder' && _jsx(TMCopyToFolderForm, { mode: openCopyToFolderForm.mode, selectedDcmtInfos: selectedDcmtInfos, onClose: () => setOpenCopyToFolderForm({ open: false, operationType: 'copyToFolder', mode: 'onlySelected' }), showTMRelationViewer: showTMRelationViewerInCopyToFolderForm }), _jsx(ConfirmFormatDialog, {}), _jsx(ConfirmAttachmentsDialog, {}), _jsx(FileSourceDialog, {}), taskFormDialogComponent, s4TViewerDialogComponent, currentCustomButton && _jsx(TMCustomButton, { button: currentCustomButton, formData: currentMetadataValues, selectedItems: selectedItemsFull, onClose: () => setCurrentCustomButton(undefined) })] }));
1266
+ }, onStatusChanged: (isModified) => { setIsModifiedBatchUpdate(isModified); } }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: approvalVID ? selectedDcmtInfos.map(item => ({ ...item, TID: approvalVID })) : selectedDcmtInfos, isReject: 0, onClose: () => updateShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: approvalVID ? selectedDcmtInfos.map(item => ({ ...item, TID: approvalVID })) : selectedDcmtInfos, isReject: 1, onClose: () => updateShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: approvalVID ? selectedDcmtInfos.map(item => ({ ...item, TID: approvalVID })) : selectedDcmtInfos, onClose: () => updateShowReAssignPopup(false) }), showMoreInfoPopup && _jsx(WorkFlowMoreInfoPopUp, { fromDTD: dtd, TID: contextConfig.approvalTID, DID: focusedItem?.DID, deviceType: deviceType, onCompleted: handleWFOperationCompleted, onClose: () => updateShowMoreInfoPopup(false), allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, triggerBlogRefresh: onRefreshBlogDatagrid }), openCopyToFolderForm.open && openCopyToFolderForm.operationType === 'mergeToPdf' && _jsx(TMMergeToPdfForm, { mode: openCopyToFolderForm.mode, selectedDcmtInfos: selectedDcmtInfos, onClose: () => setOpenCopyToFolderForm({ open: false, operationType: 'copyToFolder', mode: 'onlySelected' }), showTMRelationViewer: showTMRelationViewerInCopyToFolderForm, mergePdfManager: mergePdfManager, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), openCopyToFolderForm.open && openCopyToFolderForm.operationType === 'copyToFolder' && _jsx(TMCopyToFolderForm, { mode: openCopyToFolderForm.mode, selectedDcmtInfos: selectedDcmtInfos, onClose: () => setOpenCopyToFolderForm({ open: false, operationType: 'copyToFolder', mode: 'onlySelected' }), showTMRelationViewer: showTMRelationViewerInCopyToFolderForm, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), _jsx(ConfirmFormatDialog, {}), _jsx(ConfirmAttachmentsDialog, {}), _jsx(FileSourceDialog, {}), taskFormDialogComponent, s4TViewerDialogComponent, currentCustomButton && _jsx(TMCustomButton, { button: currentCustomButton, formData: currentMetadataValues, selectedItems: selectedItemsFull, onClose: () => setCurrentCustomButton(undefined) })] }));
1267
1267
  return {
1268
1268
  operationItems: operationItems(),
1269
1269
  renderFloatingBar,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.21.0-dev2.37",
3
+ "version": "6.21.0-dev2.39",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -40,7 +40,7 @@
40
40
  "lib"
41
41
  ],
42
42
  "dependencies": {
43
- "@topconsultnpm/sdk-ts": "6.21.0-dev2.6",
43
+ "@topconsultnpm/sdk-ts": "6.21.0-dev2.7",
44
44
  "@zip.js/zip.js": "2.8.26",
45
45
  "buffer": "^6.0.3",
46
46
  "devextreme": "^25.2.6",