@topconsultnpm/sdkui-react 6.21.0-dev2.35 → 6.21.0-dev2.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/editors/TMTextBox.d.ts +2 -0
- package/lib/components/editors/TMTextBox.js +3 -3
- package/lib/components/features/documents/TMCopyToFolderForm.d.ts +16 -0
- package/lib/components/features/documents/TMCopyToFolderForm.js +306 -0
- package/lib/components/features/documents/TMDownloadRelationViewerSection.d.ts +15 -0
- package/lib/components/features/documents/TMDownloadRelationViewerSection.js +155 -0
- package/lib/components/features/documents/TMMasterDetailDcmts.d.ts +4 -0
- package/lib/components/features/documents/TMMasterDetailDcmts.js +6 -5
- package/lib/components/features/documents/TMMergeToPdfForm.d.ts +18 -0
- package/lib/components/features/documents/TMMergeToPdfForm.js +164 -0
- package/lib/components/features/documents/TMRelationViewer.d.ts +13 -0
- package/lib/components/features/documents/TMRelationViewer.js +75 -6
- package/lib/components/features/documents/copyAndMergeDcmtsShared.d.ts +53 -0
- package/lib/components/features/documents/copyAndMergeDcmtsShared.js +262 -0
- package/lib/components/features/search/TMSearch.d.ts +2 -0
- package/lib/components/features/search/TMSearch.js +2 -2
- package/lib/components/features/search/TMSearchResult.d.ts +2 -0
- package/lib/components/features/search/TMSearchResult.js +3 -2
- package/lib/helper/SDKUI_Globals.d.ts +15 -0
- package/lib/helper/SDKUI_Globals.js +15 -1
- package/lib/helper/TMUtils.d.ts +19 -0
- package/lib/helper/ZipManager.d.ts +56 -0
- package/lib/helper/ZipManager.js +104 -0
- package/lib/helper/index.d.ts +1 -0
- package/lib/helper/index.js +1 -0
- package/lib/hooks/useDcmtOperations.d.ts +8 -2
- package/lib/hooks/useDcmtOperations.js +29 -20
- package/lib/hooks/useDocumentOperations.d.ts +4 -0
- package/lib/hooks/useDocumentOperations.js +75 -7
- package/package.json +2 -2
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { ITMEditorBase } from '../base/TMEditorBase';
|
|
3
3
|
export type TextBoxType = 'text' | 'email' | 'password' | 'number' | 'secureText';
|
|
4
4
|
export interface ITMTextBox extends ITMEditorBase {
|
|
5
|
+
autoComplete?: string;
|
|
5
6
|
autoFocus?: boolean;
|
|
6
7
|
formulaItems?: string[];
|
|
7
8
|
maxValue?: number;
|
|
@@ -13,6 +14,7 @@ export interface ITMTextBox extends ITMEditorBase {
|
|
|
13
14
|
value?: string | number;
|
|
14
15
|
fromModal?: boolean;
|
|
15
16
|
allowedPattern?: RegExp;
|
|
17
|
+
onClick?: () => void;
|
|
16
18
|
onValueChanged?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
17
19
|
onBlur?: (value: string | undefined) => void;
|
|
18
20
|
}
|
|
@@ -34,7 +34,7 @@ const StyledTextBoxEditorButton = styled.div `
|
|
|
34
34
|
border-bottom-color: ${TMColors.primary};
|
|
35
35
|
}
|
|
36
36
|
`;
|
|
37
|
-
const TMTextBox = ({ autoFocus, maxLength, labelColor, precision, fromModal = false, scale, showClearButton, validationItems = [], label = '', readOnly = false, formulaItems = [], buttons = [], isModifiedWhen, placeHolder, elementStyle, width = '100%', maxValue, minValue, fontSize = FontSize.defaultFontSize, icon, labelPosition = 'left', value, disabled = false, type = 'text', onValueChanged, onBlur, borderRadius, allowedPattern }) => {
|
|
37
|
+
const TMTextBox = ({ autoComplete = 'off', autoFocus, maxLength, labelColor, precision, fromModal = false, scale, showClearButton, validationItems = [], label = '', readOnly = false, formulaItems = [], buttons = [], isModifiedWhen, placeHolder, elementStyle, width = '100%', maxValue, minValue, fontSize = FontSize.defaultFontSize, icon, labelPosition = 'left', value, disabled = false, type = 'text', onClick, onValueChanged, onBlur, borderRadius, allowedPattern }) => {
|
|
38
38
|
const [initialType, setInitialType] = useState(type);
|
|
39
39
|
const [currentType, setCurrentType] = useState(type);
|
|
40
40
|
const [currentValue, setCurrentValue] = useState(value);
|
|
@@ -277,13 +277,13 @@ const TMTextBox = ({ autoFocus, maxLength, labelColor, precision, fromModal = fa
|
|
|
277
277
|
return 6 + (buttonCount * buttonWidth) + 8;
|
|
278
278
|
}
|
|
279
279
|
};
|
|
280
|
-
return (_jsxs("div", { style: { width: '100%', height: 'fit-content' }, id: `text-${id}`, children: [_jsx(StyledEditor, { ref: inputRef, onContextMenu: (e) => e.stopPropagation(), id: `text-${label}-${id}`, name: label, autoFocus: autoFocus, readOnly: readOnly, type: currentType, disabled: disabled, value: displayedValue, width: width || '100%', placeholder: placeHolder, maxLength: maxLength, autoComplete:
|
|
280
|
+
return (_jsxs("div", { style: { width: '100%', height: 'fit-content', cursor: onClick ? 'pointer' : undefined }, id: `text-${id}`, onClick: onClick, children: [_jsx(StyledEditor, { ref: inputRef, onContextMenu: (e) => e.stopPropagation(), id: `text-${label}-${id}`, name: label, autoFocus: autoFocus, readOnly: readOnly, type: currentType, disabled: disabled, value: displayedValue, width: width || '100%', placeholder: placeHolder, maxLength: maxLength, autoComplete: autoComplete, spellCheck: false, onFocus: () => setIsFocused(true), onBlur: (e) => { setIsFocused(false); if (currentValue != value)
|
|
281
281
|
onBlur?.(currentValue); }, onChange: handleInputChange, onKeyDown: (e) => {
|
|
282
282
|
if (currentType === 'number') {
|
|
283
283
|
if (!scale && (e.key == "." || e.key == ","))
|
|
284
284
|
e.preventDefault();
|
|
285
285
|
}
|
|
286
|
-
}, "$isMobile": deviceType === DeviceType.MOBILE, "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, "$fontSize": fontSize, "$maxValue": maxValue, "$width": width, "$type": currentType, "$borderRadius": borderRadius, style: { paddingRight: `${calculateRightPadding()}px
|
|
286
|
+
}, "$isMobile": deviceType === DeviceType.MOBILE, "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, "$fontSize": fontSize, "$maxValue": maxValue, "$width": width, "$type": currentType, "$borderRadius": borderRadius, style: { paddingRight: `${calculateRightPadding()}px`, cursor: onClick ? 'pointer' : undefined } }), (initialType === 'password' || initialType === 'secureText') && _jsx(StyledShowPasswordIcon, { onClick: toggleShowPassword, "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, children: showPasswordIcon() }), initialType !== 'password' &&
|
|
287
287
|
_jsxs("div", { style: { display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', position: 'absolute', right: type === 'number' ? '25px' : '6px', top: label.length > 0 ? '20px' : '3px', pointerEvents: disabled ? 'none' : 'auto', opacity: disabled ? 0.4 : 1 }, children: [formulaItems.length > 0 &&
|
|
288
288
|
_jsx(StyledTextBoxEditorButton, { onClick: () => {
|
|
289
289
|
setShowFormulaItemsChooser(true);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DcmtInfo } from '../../../ts';
|
|
3
|
+
import { TMCopyToFolderMode } from '../../../hooks/useDocumentOperations';
|
|
4
|
+
interface ITMCopyToFolderFormProps {
|
|
5
|
+
mode: TMCopyToFolderMode;
|
|
6
|
+
selectedDcmtInfos: Array<DcmtInfo>;
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
showTMRelationViewer: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Form per la copia/zip dei documenti in una cartella locale.
|
|
12
|
+
* Logica condivisa con TMMergeToPdfForm è esternalizzata in copyAndMergeDcmtsShared
|
|
13
|
+
* e TMDownloadRelationViewerSection.
|
|
14
|
+
*/
|
|
15
|
+
declare const TMCopyToFolderForm: React.FC<ITMCopyToFolderFormProps>;
|
|
16
|
+
export default TMCopyToFolderForm;
|
|
@@ -0,0 +1,306 @@
|
|
|
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_HALF, } 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 }) => {
|
|
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: 'Solo i documenti selezionati',
|
|
50
|
+
customized: 'Documenti di primo livello e i correlati selezionati',
|
|
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
|
+
await ZipManager.createAndDownload(zipEntries, zipFileName, {
|
|
199
|
+
compressionLevel: 6,
|
|
200
|
+
password: settings.zipPassword.trim() || undefined,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
TMMessageBoxManager.show({ message: 'Modalità di esportazione non supportata.', buttons: [ButtonNames.OK] });
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
onClose();
|
|
209
|
+
};
|
|
210
|
+
// ---- Layout salva/rimuovi ----
|
|
211
|
+
const saveLayout = () => {
|
|
212
|
+
const { zipPassword, ...settingsToSave } = settings;
|
|
213
|
+
SDKUI_Globals.userSettings.documentDownloadSettings = { ...settingsToSave, zipPassword: '' };
|
|
214
|
+
const defaults = new DocumentDownloadSettings();
|
|
215
|
+
const hasChanges = JSON.stringify(settings) !== JSON.stringify(defaults);
|
|
216
|
+
if (hasChanges) {
|
|
217
|
+
setHasSavedLayout(true);
|
|
218
|
+
ShowAlert({ mode: 'success', message: 'Layout salvato con successo', title: 'Successo', duration: 3000 });
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
const removeLayout = () => {
|
|
222
|
+
const defaults = new DocumentDownloadSettings();
|
|
223
|
+
SDKUI_Globals.userSettings.documentDownloadSettings = { ...defaults };
|
|
224
|
+
setSettings(defaults);
|
|
225
|
+
folderHandleRef.current = null;
|
|
226
|
+
setHasSavedLayout(false);
|
|
227
|
+
ShowAlert({ mode: 'success', message: 'Layout rimosso con successo', title: 'Successo', duration: 3000 });
|
|
228
|
+
};
|
|
229
|
+
const isLayoutSameAsSaved = () => {
|
|
230
|
+
const saved = SDKUI_Globals.userSettings.documentDownloadSettings;
|
|
231
|
+
if (!saved) {
|
|
232
|
+
const defaults = new DocumentDownloadSettings();
|
|
233
|
+
return JSON.stringify(settings) === JSON.stringify(defaults);
|
|
234
|
+
}
|
|
235
|
+
return JSON.stringify(settings) === JSON.stringify(saved);
|
|
236
|
+
};
|
|
237
|
+
// ---- Render della sezione configurazione ----
|
|
238
|
+
const configSection = (_jsxs("div", { style: {
|
|
239
|
+
position: 'relative',
|
|
240
|
+
border: `1px solid ${TMColors.border_normal}`,
|
|
241
|
+
borderRadius: '8px',
|
|
242
|
+
padding: '8px',
|
|
243
|
+
height: showTMRelationViewer ? '100%' : undefined,
|
|
244
|
+
flex: showTMRelationViewer ? undefined : 1,
|
|
245
|
+
minHeight: 0,
|
|
246
|
+
marginTop: showTMRelationViewer ? '10px' : undefined,
|
|
247
|
+
display: 'flex',
|
|
248
|
+
flexDirection: 'column',
|
|
249
|
+
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: [
|
|
251
|
+
{ value: 'copy', display: 'Copia in una cartella' },
|
|
252
|
+
{ 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: [
|
|
254
|
+
{
|
|
255
|
+
icon: _jsx(IconFolderOpen, {}),
|
|
256
|
+
text: 'Seleziona cartella',
|
|
257
|
+
onClick: handleSelectFolder
|
|
258
|
+
},
|
|
259
|
+
...(!isUsingDefaultDownloads ? [{
|
|
260
|
+
icon: _jsx(IconUndo, {}),
|
|
261
|
+
text: 'Ripristina Download',
|
|
262
|
+
onClick: () => {
|
|
263
|
+
skipSelectFolderRef.current = true;
|
|
264
|
+
updateSettings('destinationFolder', 'Download');
|
|
265
|
+
folderHandleRef.current = null;
|
|
266
|
+
}
|
|
267
|
+
}] : [])
|
|
268
|
+
] }), 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: {
|
|
269
|
+
display: 'flex',
|
|
270
|
+
alignItems: 'center',
|
|
271
|
+
gap: '8px',
|
|
272
|
+
padding: '8px 12px',
|
|
273
|
+
border: `1px solid ${TMColors.border_normal}`,
|
|
274
|
+
borderRadius: '5px',
|
|
275
|
+
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: [
|
|
281
|
+
{ value: 'onlyDid', display: 'Solo DID' },
|
|
282
|
+
{ value: 'documentTypeAndDid', display: 'Nome tipo documento e DID' },
|
|
283
|
+
{ value: 'documentTypeAndCustomMetadata', display: 'Nome tipo documento e metadati personalizzati' },
|
|
284
|
+
{ value: 'onlyCustomMetadata', display: 'Solo metadati personalizzati' },
|
|
285
|
+
], 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: {
|
|
286
|
+
width: '32px',
|
|
287
|
+
height: '28px',
|
|
288
|
+
textAlign: 'center',
|
|
289
|
+
fontSize: '14px',
|
|
290
|
+
fontWeight: 500,
|
|
291
|
+
padding: '4px',
|
|
292
|
+
border: `1px solid ${TMColors.border_normal}`,
|
|
293
|
+
borderRadius: '5px',
|
|
294
|
+
outline: 'none',
|
|
295
|
+
color: 'black',
|
|
296
|
+
background: 'white',
|
|
297
|
+
}, onFocus: (e) => {
|
|
298
|
+
e.target.style.backgroundImage = 'linear-gradient(white, #E4E9F7)';
|
|
299
|
+
e.target.style.borderBottom = `2px solid ${TMColors.primary}`;
|
|
300
|
+
}, onBlur: (e) => {
|
|
301
|
+
e.target.style.backgroundImage = 'none';
|
|
302
|
+
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 })] })] }) }) }));
|
|
305
|
+
};
|
|
306
|
+
export default TMCopyToFolderForm;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DcmtInfo } from '../../../ts';
|
|
3
|
+
import { IRelatedDcmt } from './TMMasterDetailDcmts';
|
|
4
|
+
interface ITMDownloadRelationViewerSectionProps {
|
|
5
|
+
selectedDcmtInfos: Array<DcmtInfo>;
|
|
6
|
+
/** Notifica al parent la lista dei documenti correlati selezionati (deduplicati) */
|
|
7
|
+
onSelectionChanged: (items: Array<IRelatedDcmt>) => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Sezione condivisa tra TMCopyToFolderForm e TMMergeToPdfForm
|
|
11
|
+
* che mostra l'elenco dei documenti correlati e il tree di selezione
|
|
12
|
+
* per tipo documento / "solo metadati".
|
|
13
|
+
*/
|
|
14
|
+
declare const TMDownloadRelationViewerSection: React.FC<ITMDownloadRelationViewerSectionProps>;
|
|
15
|
+
export default TMDownloadRelationViewerSection;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useRef, useState } from 'react';
|
|
3
|
+
import TreeView from 'devextreme-react/tree-view';
|
|
4
|
+
import { SDKUI_Localizator } from '../../../helper';
|
|
5
|
+
import { TMColors } from '../../../utils/theme';
|
|
6
|
+
import { TMSplitterLayout } from '../../base/TMLayout';
|
|
7
|
+
import TMRelationViewer from './TMRelationViewer';
|
|
8
|
+
import { dedupeByTidDid, getDcmtKey, getFloatingLabelStyle, SPLITTER_MIN, SPLITTER_START_65_35, } from './copyAndMergeDcmtsShared';
|
|
9
|
+
/**
|
|
10
|
+
* Sezione condivisa tra TMCopyToFolderForm e TMMergeToPdfForm
|
|
11
|
+
* che mostra l'elenco dei documenti correlati e il tree di selezione
|
|
12
|
+
* per tipo documento / "solo metadati".
|
|
13
|
+
*/
|
|
14
|
+
const TMDownloadRelationViewerSection = ({ selectedDcmtInfos, onSelectionChanged, }) => {
|
|
15
|
+
const [focusedItem, setFocusedItem] = useState(null);
|
|
16
|
+
const [selectedItems, setSelectedItems] = useState([]);
|
|
17
|
+
const [allItems, setAllItems] = useState([]);
|
|
18
|
+
const didInitSelectionRef = useRef(false);
|
|
19
|
+
const updateSelection = useCallback((items) => {
|
|
20
|
+
const deduped = dedupeByTidDid(items);
|
|
21
|
+
setSelectedItems(deduped);
|
|
22
|
+
onSelectionChanged(deduped);
|
|
23
|
+
}, [onSelectionChanged]);
|
|
24
|
+
const handleFocusedItemChanged = useCallback((item) => {
|
|
25
|
+
setFocusedItem(item);
|
|
26
|
+
}, []);
|
|
27
|
+
const handleSelectedItemsChanged = useCallback((items) => {
|
|
28
|
+
updateSelection(items);
|
|
29
|
+
}, [updateSelection]);
|
|
30
|
+
const handleAllItemsChanged = useCallback((items) => {
|
|
31
|
+
setAllItems(items);
|
|
32
|
+
if (!didInitSelectionRef.current && items.some(i => i.isDcmt)) {
|
|
33
|
+
didInitSelectionRef.current = true;
|
|
34
|
+
updateSelection(items.filter(i => i.isDcmt));
|
|
35
|
+
}
|
|
36
|
+
}, [updateSelection]);
|
|
37
|
+
return (_jsx("div", { style: {
|
|
38
|
+
position: 'relative',
|
|
39
|
+
height: '100%',
|
|
40
|
+
minHeight: 0,
|
|
41
|
+
display: 'flex',
|
|
42
|
+
flexDirection: 'column',
|
|
43
|
+
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 : []);
|
|
129
|
+
}
|
|
130
|
+
else if (itemData.id === 'metadataOnly') {
|
|
131
|
+
if (itemData.selected) {
|
|
132
|
+
updateSelection([...selectedItems, ...metadataOnlyItems]);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
const metadataKeys = new Set(metadataOnlyItems.map(getDcmtKey));
|
|
136
|
+
updateSelection(selectedItems.filter(item => !metadataKeys.has(getDcmtKey(item))));
|
|
137
|
+
}
|
|
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]);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
const groupKeys = new Set(groupItems.map(getDcmtKey));
|
|
147
|
+
updateSelection(selectedItems.filter(item => !groupKeys.has(getDcmtKey(item))));
|
|
148
|
+
}
|
|
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") }) }));
|
|
154
|
+
};
|
|
155
|
+
export default TMDownloadRelationViewerSection;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { HomeBlogPost, SearchResultDescriptor, TaskDescriptor } from '@topconsultnpm/sdk-ts';
|
|
3
|
+
import { RelationTreeItem } from './TMRelationViewer';
|
|
4
|
+
import { MergePdfManagerType } from '../../../helper';
|
|
3
5
|
import { DcmtInfo, TaskContext, MetadataValueDescriptorEx } from '../../../ts';
|
|
4
6
|
import { DeviceContextProps } from '../../base/TMDeviceProvider';
|
|
7
|
+
export type IRelatedDcmt = RelationTreeItem;
|
|
5
8
|
interface ITMMasterDetailDcmtsProps extends DeviceContextProps {
|
|
6
9
|
allTasks?: Array<TaskDescriptor>;
|
|
7
10
|
getAllTasks?: () => Promise<void>;
|
|
@@ -26,6 +29,7 @@ interface ITMMasterDetailDcmtsProps extends DeviceContextProps {
|
|
|
26
29
|
openS4TViewer?: boolean;
|
|
27
30
|
onOpenS4TViewerRequest?: (dcmtInfo: Array<DcmtInfo>, refreshDocumentPreview?: (() => Promise<void>)) => void;
|
|
28
31
|
onOpenPdfEditorRequest?: ((dcmtInfo: Array<DcmtInfo>, refreshDocumentPreview?: () => Promise<void>) => void);
|
|
32
|
+
mergePdfManager?: MergePdfManagerType;
|
|
29
33
|
datagridUtility?: {
|
|
30
34
|
onRefreshSearchAsyncDatagrid?: () => Promise<void>;
|
|
31
35
|
onRefreshDataRowsAsync?: (() => Promise<void>);
|