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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +2 -2
  2. package/lib/components/NewComponents/ContextMenu/styles.d.ts +43 -19
  3. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +1 -1
  4. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +79 -27
  5. package/lib/components/base/Styled.d.ts +76 -40
  6. package/lib/components/base/TMAreaManager.js +28 -11
  7. package/lib/components/base/TMFileManagerDataGridView.js +2 -2
  8. package/lib/components/base/TMFileManagerUtils.d.ts +6 -2
  9. package/lib/components/base/TMPanel.js +1 -0
  10. package/lib/components/base/TMTreeView.d.ts +5 -3
  11. package/lib/components/choosers/TMDataListItemChooser.js +25 -2
  12. package/lib/components/choosers/TMDynDataListItemChooser.d.ts +1 -1
  13. package/lib/components/choosers/TMDynDataListItemChooser.js +50 -23
  14. package/lib/components/choosers/TMUserChooser.js +3 -1
  15. package/lib/components/editors/TMEditorStyled.d.ts +42 -10
  16. package/lib/components/editors/TMFormulaEditor.js +15 -3
  17. package/lib/components/editors/TMMetadataEditor.js +4 -3
  18. package/lib/components/editors/TMMetadataValues.js +1 -1
  19. package/lib/components/features/archive/TMArchive.js +1 -1
  20. package/lib/components/features/documents/TMDcmtBlog.d.ts +1 -0
  21. package/lib/components/features/documents/TMDcmtBlog.js +2 -2
  22. package/lib/components/features/documents/TMDcmtForm.js +11 -7
  23. package/lib/components/features/documents/TMDcmtPreview.d.ts +5 -3
  24. package/lib/components/features/documents/TMDragDropOverlay.js +7 -2
  25. package/lib/components/features/documents/TMFileUploader.js +4 -1
  26. package/lib/components/features/documents/TMMasterDetailDcmts.js +74 -21
  27. package/lib/components/features/documents/TMRelationViewer.d.ts +6 -1
  28. package/lib/components/features/documents/TMRelationViewer.js +44 -7
  29. package/lib/components/features/search/TMSavedQuerySelector.js +1 -1
  30. package/lib/components/features/search/TMSearch.js +2 -0
  31. package/lib/components/features/search/TMSearchQueryEditor.js +13 -1
  32. package/lib/components/features/search/TMSearchQueryPanel.d.ts +3 -3
  33. package/lib/components/features/search/TMSearchResult.js +16 -3
  34. package/lib/components/features/search/TMViewHistoryDcmt.js +6 -0
  35. package/lib/components/features/workflow/diagram/DiagramItemForm.js +5 -1
  36. package/lib/components/features/workflow/diagram/WFDiagram.js +7 -1
  37. package/lib/components/features/workflow/diagram/WorkitemRecipientsEditor.d.ts +1 -1
  38. package/lib/components/features/workflow/diagram/xmlParser.js +13 -14
  39. package/lib/components/forms/Login/ChangePasswordInputs.d.ts +1 -1
  40. package/lib/components/forms/Login/TMLoginForm.js +15 -5
  41. package/lib/components/forms/TMChooserForm.js +25 -2
  42. package/lib/components/grids/TMBlogsPost.js +1 -1
  43. package/lib/components/index.d.ts +1 -0
  44. package/lib/components/index.js +1 -0
  45. package/lib/components/layout/panelManager/TMPanelManagerToolbar.d.ts +5 -2
  46. package/lib/components/pages/TMPage.js +4 -2
  47. package/lib/components/query/TMQueryCountButton.d.ts +11 -0
  48. package/lib/components/query/TMQueryCountButton.js +32 -0
  49. package/lib/components/query/TMQueryEditor.d.ts +10 -6
  50. package/lib/components/query/TMQueryEditor.js +41 -4
  51. package/lib/components/query/TMQuerySummary.js +3 -2
  52. package/lib/components/sidebar/TMCommandsPanel.d.ts +4 -2
  53. package/lib/components/viewers/TMDataListItemViewer.d.ts +2 -1
  54. package/lib/components/viewers/TMDataListItemViewer.js +2 -2
  55. package/lib/helper/SDKUI_Globals.d.ts +2 -0
  56. package/lib/helper/TMUtils.d.ts +4 -3
  57. package/lib/helper/TMUtils.js +12 -0
  58. package/lib/helper/checkinCheckoutManager.d.ts +1 -1
  59. package/lib/helper/checkinCheckoutManager.js +18 -4
  60. package/lib/hooks/useDcmtOperations.d.ts +1 -0
  61. package/lib/hooks/useDcmtOperations.js +75 -4
  62. package/lib/hooks/useDocumentOperations.js +13 -8
  63. package/lib/hooks/useForm.js +20 -14
  64. package/lib/hooks/useInputDialog.d.ts +2 -0
  65. package/lib/hooks/useInputDialog.js +34 -0
  66. package/lib/hooks/useQueryParametersDialog.js +5 -5
  67. package/package.json +55 -55
@@ -259,8 +259,9 @@ export const getDcmtCicoStatus = (dcmt, allUsers, dtd) => {
259
259
  let checkoutDate;
260
260
  let version = 1;
261
261
  let fileExt;
262
+ let isMetadata = false;
262
263
  // ========================================================================
263
- // CASO 1: Documento come Array di MetadataValueDescriptorEx
264
+ // CASO 1: Documento come Array di MetadataValueDescriptorEx: Form del documento
264
265
  // ========================================================================
265
266
  // Questo formato viene utilizzato quando il documento proviene da query
266
267
  // o liste dove ogni metadato è un oggetto separato con proprietà 'md' e 'value'
@@ -279,9 +280,11 @@ export const getDcmtCicoStatus = (dcmt, allUsers, dtd) => {
279
280
  version = (versionRaw != null && !isNaN(Number(versionRaw))) ? Number(versionRaw) : 1;
280
281
  const fileExtProperty = dcmtsArray.find((item) => item.mid === SystemMIDsAsNumber.FileExt);
281
282
  fileExt = fileExtProperty?.value ? fileExtProperty.value.toString() : null;
283
+ const fileCountProperty = dcmtsArray.find((item) => item.mid === SystemMIDsAsNumber.FileCount);
284
+ isMetadata = !(fileCountProperty?.value && Number(fileCountProperty.value) > 0);
282
285
  }
283
286
  // ========================================================================
284
- // CASO 2: Documento come Oggetto Piatto (formato standard)
287
+ // CASO 2: Documento come Oggetto Piatto (formato standard): Risultato della ricerca
285
288
  // ========================================================================
286
289
  // Questo formato viene utilizzato quando il documento ha proprietà dirette
287
290
  // nel formato chiave-valore: TID, DID, e "TID_MetadataID" per i metadati
@@ -290,6 +293,8 @@ export const getDcmtCicoStatus = (dcmt, allUsers, dtd) => {
290
293
  const CICO_CheckoutUserID_Meta = dtd.metadata?.find(md => md.name === CICO_MetadataNames.CICO_CheckoutUserID);
291
294
  const CICO_CheckoutDate_Meta = dtd.metadata?.find(md => md.name === CICO_MetadataNames.CICO_CheckoutDate);
292
295
  const CICO_Version_Meta = dtd.metadata?.find(md => md.name === CICO_MetadataNames.CICO_Version);
296
+ const fileCountValue = dcmt.FILECOUNT != null ? Number(dcmt.FILECOUNT) : NaN;
297
+ isMetadata = isNaN(fileCountValue) || fileCountValue <= 0;
293
298
  fileExt = dcmt.FILEEXT ? dcmt.FILEEXT.toString() : null;
294
299
  // Estrai l'ID dell'utente che ha effettuato il checkout
295
300
  if (CICO_CheckoutUserID_Meta?.id) {
@@ -310,6 +315,15 @@ export const getDcmtCicoStatus = (dcmt, allUsers, dtd) => {
310
315
  }
311
316
  }
312
317
  // ========================================================================
318
+ // EARLY RETURN: Documento di soli metadati (senza file)
319
+ // ========================================================================
320
+ if (isMetadata) {
321
+ return {
322
+ cicoEnabled: false,
323
+ checkoutStatus: { isCheckedOut: false, mode: '', version: 1, icon: null, editLockTooltipText: null }
324
+ };
325
+ }
326
+ // ========================================================================
313
327
  // COSTRUZIONE DELLO STATO DI CHECKOUT
314
328
  // ========================================================================
315
329
  let checkoutStatus = {
@@ -345,8 +359,8 @@ export const getDcmtCicoStatus = (dcmt, allUsers, dtd) => {
345
359
  // RESTITUZIONE RISULTATO FINALE
346
360
  // ========================================================================
347
361
  return {
348
- // CICO è abilitato se configurato nel DTD e l'utente ha i permessi
349
- cicoEnabled: cicoInfo.CICO === 1 && cicoInfo.CanCICO === AccessLevels.Yes && fileExt !== null && fileExt !== '',
362
+ // CICO è abilitato se configurato nel DTD, l'utente ha i permessi e il documento non è di soli metadati
363
+ cicoEnabled: cicoInfo.CICO === 1 && cicoInfo.CanCICO === AccessLevels.Yes && fileExt !== null && fileExt !== '' && !isMetadata,
350
364
  checkoutStatus: checkoutStatus
351
365
  };
352
366
  };
@@ -21,5 +21,6 @@ export interface UseDcmtOperationsReturn {
21
21
  removeDcmtsFileCache: (key: string) => void;
22
22
  isDcmtFileInCache: (key: string) => boolean;
23
23
  runOperationAsync: (inputDcmts: DcmtInfo[] | undefined, dcmtOperationType: DcmtOperationTypes, actionAfterOperationAsync?: () => Promise<void>) => Promise<void>;
24
+ FileSourceDialog: () => JSX.Element;
24
25
  }
25
26
  export declare const useDcmtOperations: () => UseDcmtOperationsReturn;
@@ -4,9 +4,19 @@ import { SDK_Globals, RetrieveFileOptions, DcmtOpers, ResultTypes, RecentCategor
4
4
  import { ShowAlert, TMResultManager, FormulaHelper, TMExceptionBoxManager, TMSpinner } from '../components';
5
5
  import { Globalization, getExceptionMessage, dialogConfirmOperation, extensionHandler, downloadBase64File, SDKUI_Globals, dcmtsFileCacheDownload, CACHE_SIZE_LIMIT, clearDcmtsFileCache, dcmtsFileCachePreview, isDcmtFileInCache, removeDcmtsFileCache, SDKUI_Localizator } from '../helper';
6
6
  import { DcmtOperationTypes, DownloadTypes, FileExtensionHandler } from '../ts';
7
- import { useFileDialog } from './useInputDialog';
7
+ import { useFileDialog, useFileSourceDialog } from './useInputDialog';
8
8
  import { isXMLFileExt } from '../helper/dcmtsHelper';
9
9
  import { ShowConfirm } from '../components/base/TMConfirm';
10
+ import { useBetaFeatures } from './useBetaFeatures';
11
+ const isScannerLicenseConfigured = () => {
12
+ try {
13
+ const scannerLicense = SDKUI_Globals.userSettings.advancedSettings.scannerLicense;
14
+ return scannerLicense && scannerLicense.trim() !== '';
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ };
10
20
  let abortController = new AbortController();
11
21
  const downloadCountMap = new Map();
12
22
  const getDownloadFileName = (fileName) => {
@@ -32,6 +42,8 @@ export const useDcmtOperations = () => {
32
42
  const [waitPanelValueSecondary, setWaitPanelValueSecondary] = useState(0);
33
43
  const [waitPanelMaxValueSecondary, setWaitPanelMaxValueSecondary] = useState(0);
34
44
  const { OpenFileDialog } = useFileDialog();
45
+ const isBetaFeaturesEnabled = useBetaFeatures();
46
+ const [selectFileSource, FileSourceDialog] = useFileSourceDialog();
35
47
  const _downloadDcmtsAsync = async (inputDcmts, downloadMode = "download", onFileDownloaded, skipConfirmation = false) => {
36
48
  if (inputDcmts === undefined)
37
49
  return;
@@ -210,7 +222,60 @@ export const useDcmtOperations = () => {
210
222
  return;
211
223
  if (inputDcmts.length <= 0)
212
224
  return;
213
- let file = inputDcmts[0].FILE ?? await OpenFileDialog();
225
+ let file = inputDcmts[0].FILE;
226
+ if (!file) {
227
+ if (isBetaFeaturesEnabled && isScannerLicenseConfigured()) {
228
+ const source = await selectFileSource();
229
+ if (!source)
230
+ return;
231
+ switch (source) {
232
+ case 'filesystem':
233
+ file = await OpenFileDialog();
234
+ break;
235
+ case 'scanner-new':
236
+ if (SDKUI_Globals.scanRequestHandler) {
237
+ file = await new Promise((resolve) => {
238
+ SDKUI_Globals.scanRequestHandler('new', (scannedFile) => resolve(scannedFile), () => resolve(undefined));
239
+ });
240
+ }
241
+ else {
242
+ ShowAlert({ message: 'Funzionalità scanner non disponibile in questo contesto.', mode: 'info', duration: 3000, title: 'Scanner' });
243
+ return;
244
+ }
245
+ break;
246
+ case 'scanner-edit':
247
+ if (SDKUI_Globals.scanRequestHandler) {
248
+ // Download the existing file from the document
249
+ let existingFile;
250
+ try {
251
+ const rfo = new RetrieveFileOptions();
252
+ rfo.retrieveReason = DcmtOpers.None;
253
+ const retrievedFile = await SDK_Globals.tmSession?.NewSearchEngine().RetrieveFileAsync(inputDcmts[0].TID, inputDcmts[0].DID, rfo);
254
+ existingFile = retrievedFile;
255
+ }
256
+ catch (ex) {
257
+ TMExceptionBoxManager.show({ exception: getExceptionMessage(ex) });
258
+ return;
259
+ }
260
+ if (!existingFile) {
261
+ ShowAlert({ message: 'Impossibile recuperare il file del documento.', mode: 'warning', duration: 3000, title: 'Scanner' });
262
+ return;
263
+ }
264
+ file = await new Promise((resolve) => {
265
+ SDKUI_Globals.scanRequestHandler('edit', (scannedFile) => resolve(scannedFile), () => resolve(undefined), existingFile);
266
+ });
267
+ }
268
+ else {
269
+ ShowAlert({ message: 'Funzionalità scanner non disponibile in questo contesto.', mode: 'info', duration: 3000, title: 'Scanner' });
270
+ return;
271
+ }
272
+ break;
273
+ }
274
+ }
275
+ else {
276
+ file = await OpenFileDialog();
277
+ }
278
+ }
214
279
  if (!file)
215
280
  return;
216
281
  setShowWaitPanel(true);
@@ -489,10 +554,16 @@ export const useDcmtOperations = () => {
489
554
  actionAfterOperationAsync?.();
490
555
  TMResultManager.show(result, operationTitle, "TID", "DID");
491
556
  };
492
- dialogConfirmOperation(operationTitle, msg, doOperationAsync);
557
+ // Per SubstituteFile con beta features e scanner, non mostrare conferma
558
+ if (dcmtOperationType === DcmtOperationTypes.SubstituteFile && isBetaFeaturesEnabled && isScannerLicenseConfigured()) {
559
+ await doOperationAsync();
560
+ }
561
+ else {
562
+ dialogConfirmOperation(operationTitle, msg, doOperationAsync);
563
+ }
493
564
  };
494
565
  return {
495
566
  abortController, showWaitPanel, showPrimary, waitPanelTitle, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary,
496
- downloadDcmtsAsync, getDcmtFileAsync, clearDcmtsFileCache, removeDcmtsFileCache, isDcmtFileInCache, runOperationAsync
567
+ downloadDcmtsAsync, getDcmtFileAsync, clearDcmtsFileCache, removeDcmtsFileCache, isDcmtFileInCache, runOperationAsync, FileSourceDialog
497
568
  };
498
569
  };
@@ -105,10 +105,11 @@ export const useDocumentOperations = (props) => {
105
105
  }, [refreshOperationsTrigger]);
106
106
  // Context helpers
107
107
  const isDcmtFormContext = context === SearchResultContext.DCMT_FORM;
108
+ const isMasterDetailContext = context === SearchResultContext.MASTER_DETAIL;
108
109
  const { showHistory, showHistoryCallback, hideHistoryCallback, showCheckoutInformationForm, commentFormState, hideCommentFormCallback, showCheckoutInformationFormCallback, hideCheckoutInformationFormCallback, copyCheckoutPathToClipboardCallback, handleCheckOutCallback, handleCheckInCallback, showCicoWaitPanel, cicoWaitPanelTitle, showCicoPrimaryProgress, cicoPrimaryProgressText, cicoPrimaryProgressValue, cicoPrimaryProgressMax, } = useCheckInOutOperations({
109
110
  onRefreshPreview: onRefreshPreviewCallback
110
111
  });
111
- const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, runOperationAsync, getDcmtFileAsync, clearDcmtsFileCache, removeDcmtsFileCache, isDcmtFileInCache } = useDcmtOperations();
112
+ const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, runOperationAsync, getDcmtFileAsync, clearDcmtsFileCache, removeDcmtsFileCache, isDcmtFileInCache, FileSourceDialog } = useDcmtOperations();
112
113
  const {
113
114
  // Data
114
115
  relatedDcmts, pairedSearchResults, manyToManyRelations, selectedManyToManyRelation, manyToManyChooserDataSource, relatedDcmtsChooserDataSource,
@@ -632,7 +633,7 @@ export const useDocumentOperations = (props) => {
632
633
  const checkinMenuItem = () => {
633
634
  // Take the first document (used for validation checks)
634
635
  let dcmt = focusedItem;
635
- if (isDcmtFormContext) {
636
+ if (isDcmtFormContext || isMasterDetailContext) {
636
637
  dcmt = dcmtDataRowForCicoStatus;
637
638
  }
638
639
  const { cicoEnabled, checkoutStatus } = getDcmtCicoStatus(dcmt, allUsers, dtd);
@@ -1059,9 +1060,13 @@ export const useDocumentOperations = (props) => {
1059
1060
  disabled: isDisabledForSingleRow() && isDisabledForMultiRow(),
1060
1061
  submenu: [
1061
1062
  addToFavoriteOperation(),
1062
- openFormOperation(),
1063
+ addReplaceFileOperation(),
1064
+ fileCheckMenuItem(),
1065
+ fileConversionsMenuItem(),
1066
+ ...(SDK_Globals.tmSession?.SessionDescr?.appModuleID === AppModules.SURFER ? [createContextualTaskMenuItem()] : []),
1063
1067
  downloadFileMenuItem(),
1064
1068
  downloadXMLAttachmentsMenuItem(),
1069
+ ...(selectedDcmtInfos.length > 0 && isPdfEditorAvailable(dtd, selectedDcmtInfos[0]?.FILEEXT) && onOpenPdfEditorRequest ? [pdfEditorMenuItem(onOpenPdfEditorRequest)] : []),
1065
1070
  ]
1066
1071
  },
1067
1072
  signatureMenuItem(),
@@ -1081,6 +1086,7 @@ export const useDocumentOperations = (props) => {
1081
1086
  ...(inputDcmtFormLayoutMode === LayoutModes.Update ? [addToFavoriteOperation()] : []),
1082
1087
  addReplaceFileOperation(),
1083
1088
  openFormOperation(),
1089
+ deletetionMenuItem(),
1084
1090
  fileCheckMenuItem(),
1085
1091
  fileConversionsMenuItem(),
1086
1092
  ...(SDK_Globals.tmSession?.SessionDescr?.appModuleID === AppModules.SURFER ? [createContextualTaskMenuItem()] : []),
@@ -1090,6 +1096,7 @@ export const useDocumentOperations = (props) => {
1090
1096
  ]
1091
1097
  },
1092
1098
  signatureMenuItem(),
1099
+ checkinMenuItem(),
1093
1100
  ...((inputDcmtFormLayoutMode === LayoutModes.Update) ? [fullTextSearchMenuItem()] : []),
1094
1101
  ];
1095
1102
  };
@@ -1115,10 +1122,7 @@ export const useDocumentOperations = (props) => {
1115
1122
  };
1116
1123
  const renderFloatingBar = (floatingBarContainerRef && floatingBarContainerRef.current && allowFloatingBar && showFloatingBar && deviceType !== DeviceType.MOBILE) ? (_jsx(TMFloatingMenuBar, { containerRef: floatingBarContainerRef, contextMenuItems: operationItems(), isConstrained: true, defaultPosition: { x: 1, y: 88 }, defaultPinnedItems: ['rel-det', 'rel-mst', 'dl'], defaultOrientation: 'horizontal', hasContextMenu: false, pinnedItemIds: pinnedItemIds, onPinChange: setPinnedItemIds })) : null;
1117
1124
  const renderDcmtOperations = (_jsxs(_Fragment, { children: [(showExportForm && searchResult && dataColumns && dataSource && selectedRowKeys) && (_jsx(TMDataGridExportForm, { dataColumns: dataColumns, dataSource: dataSource, selectedRowKeys: selectedRowKeys, onCloseExportForm: () => setShowExportForm(false), searchResult: searchResult })), _jsx(StyledMultiViewPanel, { "$isVisible": isOpenDcmtForm, children: ((isOpenDcmtForm && focusedItem?.TID !== undefined && focusedItem?.DID !== undefined) &&
1118
- _jsx(TMDcmtForm, { isModal: openDcmtFormAsModal || (dcmtFormLayoutMode === LayoutModes.Ark && focusedItem?.DID !== undefined), titleModal: dtd?.name ?? '', TID: focusedItem.TID, DID: focusedItem.DID, allowButtonsRefs: true, layoutMode: dcmtFormLayoutMode, count: visibleItems?.length, itemIndex: visibleItems ? visibleItems.findIndex(o => o.rowIndex === focusedItem?.rowIndex) + 1 : undefined, canNext: canNavigateHandler ? canNavigateHandler('next') : false, canPrev: canNavigateHandler ? canNavigateHandler('prev') : false, onNext: () => onNavigateHandler && onNavigateHandler('next'), onPrev: () => onNavigateHandler && onNavigateHandler('prev'), onClose: () => {
1119
- (false);
1120
- onDcmtFormOpenChange(false, LayoutModes.Update);
1121
- }, onWFOperationCompleted: onWFOperationCompleted, onTaskCreateRequest: onTaskCreateRequest, onSavedAsyncCallback: onSavedAsyncCallback, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onOpenPdfEditorRequest: onOpenPdfEditorRequest, onReferenceClick: onReferenceClick, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, moreInfoTasks: getMoreInfoTasksForDocument(allTasks, focusedItem?.TID, focusedItem?.DID), showDcmtFormSidebar: showDcmtFormSidebar, datagridUtility: {
1125
+ _jsx(TMDcmtForm, { isModal: openDcmtFormAsModal || (dcmtFormLayoutMode === LayoutModes.Ark && focusedItem?.DID !== undefined), titleModal: dtd?.name ?? '', TID: focusedItem.TID, DID: focusedItem.DID, allowButtonsRefs: true, layoutMode: dcmtFormLayoutMode, count: visibleItems?.length, itemIndex: visibleItems ? visibleItems.findIndex(o => o.rowIndex === focusedItem?.rowIndex) + 1 : undefined, canNext: canNavigateHandler ? canNavigateHandler('next') : false, canPrev: canNavigateHandler ? canNavigateHandler('prev') : false, onNext: () => onNavigateHandler && onNavigateHandler('next'), onPrev: () => onNavigateHandler && onNavigateHandler('prev'), onClose: () => { (false); onDcmtFormOpenChange(false, LayoutModes.Update); }, onWFOperationCompleted: onWFOperationCompleted, onTaskCreateRequest: onTaskCreateRequest, onSavedAsyncCallback: onSavedAsyncCallback, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onOpenPdfEditorRequest: onOpenPdfEditorRequest, openFileUploaderPdfEditor: openFileUploaderPdfEditor, onReferenceClick: onReferenceClick, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, moreInfoTasks: getMoreInfoTasksForDocument(allTasks, focusedItem?.TID, focusedItem?.DID), showDcmtFormSidebar: showDcmtFormSidebar, datagridUtility: {
1122
1126
  onRefreshSearchAsyncDatagrid,
1123
1127
  onRefreshDataRowsAsync,
1124
1128
  refreshFocusedDataRowAsync,
@@ -1184,7 +1188,7 @@ export const useDocumentOperations = (props) => {
1184
1188
  updateBatchUpdateForm(false);
1185
1189
  setIsModifiedBatchUpdate(false);
1186
1190
  await onRefreshDataRowsAsync?.();
1187
- }, onStatusChanged: (isModified) => { setIsModifiedBatchUpdate(isModified); } }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: selectedDcmtInfos, isReject: 0, onClose: () => updateShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: selectedDcmtInfos, isReject: 1, onClose: () => updateShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: 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 }), _jsx(ConfirmFormatDialog, {}), _jsx(ConfirmAttachmentsDialog, {}), taskFormDialogComponent, s4TViewerDialogComponent, currentCustomButton && _jsx(TMCustomButton, { button: currentCustomButton, formData: currentMetadataValues, selectedItems: selectedItemsFull, onClose: () => setCurrentCustomButton(undefined) })] }));
1191
+ }, onStatusChanged: (isModified) => { setIsModifiedBatchUpdate(isModified); } }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: selectedDcmtInfos, isReject: 0, onClose: () => updateShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: selectedDcmtInfos, isReject: 1, onClose: () => updateShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: 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 }), _jsx(ConfirmFormatDialog, {}), _jsx(ConfirmAttachmentsDialog, {}), _jsx(FileSourceDialog, {}), taskFormDialogComponent, s4TViewerDialogComponent, currentCustomButton && _jsx(TMCustomButton, { button: currentCustomButton, formData: currentMetadataValues, selectedItems: selectedItemsFull, onClose: () => setCurrentCustomButton(undefined) })] }));
1188
1192
  return {
1189
1193
  operationItems: operationItems(),
1190
1194
  renderFloatingBar,
@@ -1237,6 +1241,7 @@ export const useDocumentOperations = (props) => {
1237
1241
  removeDcmtsFileCache,
1238
1242
  isDcmtFileInCache,
1239
1243
  runOperationAsync,
1244
+ FileSourceDialog,
1240
1245
  },
1241
1246
  relatedDocumentsInfo: {
1242
1247
  // Data
@@ -94,21 +94,27 @@ export function useSaveForm(formMode, id, sfo, validator, onSaved, onStatusChang
94
94
  const saveDataAsync = async (...args) => {
95
95
  if (!formData)
96
96
  return;
97
- let newId = -1;
98
- if (saveCustomAsync)
99
- newId = await saveCustomAsync();
100
- else
101
- newId = await setDataAsync?.(formMode, formData, ...args);
102
- let newData;
103
- if (sfo.loadDataAfterSave)
104
- newData = await loadDataAsync(newId, FormModes.Update);
105
- else {
106
- newData = formData;
107
- newData.id = newId;
108
- setFormData(newData);
109
- setFormDataOrig(newData);
97
+ try {
98
+ TMSpinner.show({ description: `${SDKUI_Localizator.SavingInProgress}...`, backgroundColor: 'transparent' });
99
+ let newId = -1;
100
+ if (saveCustomAsync)
101
+ newId = await saveCustomAsync();
102
+ else
103
+ newId = await setDataAsync?.(formMode, formData, ...args);
104
+ let newData;
105
+ if (sfo.loadDataAfterSave)
106
+ newData = await loadDataAsync(newId, FormModes.Update);
107
+ else {
108
+ newData = formData;
109
+ newData.id = newId;
110
+ setFormData(newData);
111
+ setFormDataOrig(newData);
112
+ }
113
+ onSaved?.(newData);
114
+ }
115
+ finally {
116
+ TMSpinner.hide();
110
117
  }
111
- onSaved?.(newData);
112
118
  };
113
119
  useEffect(() => { id && loadDataAsync(id, formMode); }, [id, formMode]);
114
120
  useEffect(() => {
@@ -7,3 +7,5 @@ export declare const useInputAttachmentsDialog: () => {
7
7
  openConfirmAttachmentsDialog: (list: FileDescriptor[]) => Promise<string[] | undefined>;
8
8
  ConfirmAttachmentsDialog: () => import("react/jsx-runtime").JSX.Element | null;
9
9
  };
10
+ export type FileSourceType = 'filesystem' | 'scanner-new' | 'scanner-edit' | undefined;
11
+ export declare const useFileSourceDialog: () => [() => Promise<FileSourceType>, () => JSX.Element];
@@ -103,3 +103,37 @@ export const useInputAttachmentsDialog = () => {
103
103
  };
104
104
  return { openConfirmAttachmentsDialog, ConfirmAttachmentsDialog };
105
105
  };
106
+ const fileSourceOptions = [
107
+ { value: 'filesystem', display: 'Da file system' },
108
+ { value: 'scanner-new', display: 'Da scanner (nuova scansione)' },
109
+ { value: 'scanner-edit', display: 'Da scanner (modifica scansione)' },
110
+ ];
111
+ export const useFileSourceDialog = () => {
112
+ const [promise, setPromise] = useState(null);
113
+ const [open, setOpen] = useState(false);
114
+ const handleClose = () => {
115
+ setOpen(false);
116
+ setPromise(null);
117
+ };
118
+ const handleConfirm = (source) => {
119
+ promise?.resolve(source);
120
+ handleClose();
121
+ };
122
+ const handleCancel = () => {
123
+ promise?.resolve(undefined);
124
+ handleClose();
125
+ };
126
+ const FileSourceDialog = () => {
127
+ const [source, setSource] = useState('filesystem');
128
+ return (open ?
129
+ _jsx(TMModal, { title: SDKUI_Localizator.AddOrSubstFile, height: "max-content", width: "320px", onClose: handleCancel, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '5px', padding: '10px', height: '100%' }, children: [_jsx(TMRadioButton, { dataSource: fileSourceOptions, direction: 'column', value: source, onValueChanged: (newValue) => { setSource(newValue); } }), _jsxs("div", { style: { display: 'flex', flexDirection: 'row', gap: '5px', paddingTop: '10px', justifyContent: 'center', alignItems: 'center', height: '50px' }, children: [_jsx(TMButton, { btnStyle: "advanced", showTooltip: false, icon: _jsx(IconApply, {}), caption: "OK", advancedColor: TMColors.tertiary, onClick: () => handleConfirm(source) }), _jsx(TMButton, { btnStyle: "advanced", showTooltip: false, icon: _jsx(IconCloseOutline, {}), caption: SDKUI_Localizator.Cancel, onClick: handleCancel })] })] }) })
130
+ : _jsx(_Fragment, {}));
131
+ };
132
+ const selectFileSource = () => {
133
+ return new Promise((resolve) => {
134
+ setOpen(true);
135
+ setPromise({ resolve });
136
+ });
137
+ };
138
+ return [selectFileSource, FileSourceDialog];
139
+ };
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from "react";
3
3
  import { QueryParameterDescriptor } from '@topconsultnpm/sdk-ts';
4
- import { TMModal, TMTextBox, TMButton } from "../components";
4
+ import { TMModal, TMTextBox, TMButton, TMCard, StyledDivHorizontal } from "../components";
5
5
  import { IconApply, IconCloseOutline, SDKUI_Localizator } from "../helper";
6
- import { TMColors } from "../utils/theme";
6
+ import { TMColors, TMMargin } from "../utils/theme";
7
7
  const paramPrefix = "{@QueryParam";
8
8
  export const useQueryParametersDialog = () => {
9
9
  const [promise, setPromise] = useState(null);
@@ -56,15 +56,15 @@ export const useQueryParametersDialog = () => {
56
56
  };
57
57
  const ConfirmQueryParamsDialog = () => {
58
58
  return (open ?
59
- _jsx(TMModal, { title: SDKUI_Localizator.QueryParamBind, height: "max-content", width: "400px", onClose: handleClose, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '5px', padding: '10px', height: '100%' }, children: [qdParams.map((qdp, index) => {
60
- return (_jsx(TMTextBox, { placeHolder: `${SDKUI_Localizator.EnterValue} ...`, label: qdp.name, autoFocus: index == 0, value: qdp.value ?? '', onValueChanged: (e) => {
59
+ _jsx(TMModal, { title: SDKUI_Localizator.QueryParamBind, height: `${qdParams.length > 0 ? (qdParams.length * 73) + 73 : 100}px`, width: "400px", onClose: handleClose, children: _jsxs(TMCard, { scrollX: true, height: "100%", children: [qdParams.map((qdp, index) => {
60
+ return (_jsx(TMTextBox, { elementStyle: { marginBottom: TMMargin.smallMargin }, placeHolder: `${SDKUI_Localizator.EnterValue} ...`, label: qdp.name, autoFocus: index == 0, value: qdp.value ?? '', onValueChanged: (e) => {
61
61
  let newQdp = qdParamsOut.find(o => o.id == qdp.id);
62
62
  if (newQdp)
63
63
  newQdp.value = e.target.value;
64
64
  else
65
65
  qdParamsOut.push({ id: qdp.id, name: qdp.name, value: e.target.value });
66
66
  } }, qdp.id));
67
- }), _jsxs("div", { style: { display: 'flex', flexDirection: 'row', gap: '5px', paddingTop: '10px', justifyContent: 'flex-end', alignItems: 'center', height: '50px' }, children: [_jsx(TMButton, { btnStyle: "advanced", showTooltip: false, icon: _jsx(IconApply, {}), caption: "OK", advancedColor: TMColors.tertiary, onClick: handleConfirm }), _jsx(TMButton, { btnStyle: "advanced", showTooltip: false, icon: _jsx(IconCloseOutline, {}), caption: SDKUI_Localizator.Cancel, onClick: handleCancel })] })] }) })
67
+ }), _jsxs(StyledDivHorizontal, { style: { gap: 10, marginBottom: TMMargin.smallMargin, width: '100%', alignItems: 'center' }, children: [_jsx(TMButton, { btnStyle: "advanced", showTooltip: false, icon: _jsx(IconApply, {}), caption: "OK", advancedColor: TMColors.tertiary, onClick: handleConfirm }), _jsx(TMButton, { btnStyle: "advanced", showTooltip: false, icon: _jsx(IconCloseOutline, {}), caption: SDKUI_Localizator.Cancel, onClick: handleCancel })] })] }) })
68
68
  : _jsx(_Fragment, {}));
69
69
  };
70
70
  return [confirmQueryParams, ConfirmQueryParamsDialog];
package/package.json CHANGED
@@ -1,57 +1,57 @@
1
1
  {
2
- "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.21.0-dev1.4",
4
- "description": "",
5
- "scripts": {
6
- "test": "echo \"Error: no test specified\" \u0026\u0026 exit 1",
7
- "clean": "powershell Remove-Item lib/ -recurse",
8
- "copy-files": "copyfiles -u 1 src/assets/*.* src/assets/ImageLibrary/*.* src/assets/thumbnails/*.* src/assets/IconsS4t/*.* src/assets/Metadata/*.* src/css/tm-sdkui.css lib/",
9
- "tm-build": "npm run clean \u0026\u0026 tsc \u0026\u0026 npm run copy-files",
10
- "tm-watch": "tsc -w",
11
- "tm-publish": "npm publish --tag latest",
12
- "tm-publish_wl": "npm publish",
13
- "storybook": "storybook dev -p 6006",
14
- "build-storybook": "storybook build"
15
- },
16
- "author": "TopConsult",
17
- "license": "ISC",
18
- "devDependencies": {
19
- "@chromatic-com/storybook": "^4.1.3",
20
- "@storybook/addon-docs": "^10.1.0",
21
- "@storybook/addon-onboarding": "^10.1.0",
22
- "@storybook/react-vite": "^10.1.0",
23
- "@types/htmlparser2": "^3.10.7",
24
- "@types/node": "^20.2.5",
25
- "@types/react": "^18.3.3",
26
- "@types/react-dom": "^18.3.3",
27
- "copyfiles": "^2.4.1",
28
- "esbuild": "^0.25.0",
29
- "react": "^18.3.1",
30
- "react-dom": "^18.3.1",
31
- "storybook": "^10.1.0",
32
- "typescript": "^5.9.3",
33
- "vite": "^6.1.1"
34
- },
35
- "main": "dist/cjs/index.js",
36
- "types": "./index.d.ts",
37
- "module": "lib/esm/index.js",
38
- "files": [
39
- "dist",
40
- "lib"
41
- ],
42
- "dependencies": {
43
- "react-router-dom": "^6.15.0",
44
- "react-pdf": "^10.3.0",
45
- "htmlparser2": "^10.0.0",
46
- "buffer": "^6.0.3",
47
- "@topconsultnpm/sdk-ts": "6.20.0",
48
- "exceljs": "^4.4.0",
49
- "devextreme": "25.2.4",
50
- "styled-components": "^6.1.1",
51
- "pdfjs-dist": "5.4.296",
52
- "devextreme-react": "25.2.4"
53
- },
54
- "overrides": {
55
- "esbuild": "^0.25.0"
56
- }
2
+ "name": "@topconsultnpm/sdkui-react",
3
+ "version": "6.21.0-dev1.41",
4
+ "description": "",
5
+ "scripts": {
6
+ "test": "echo \"Error: no test specified\" && exit 1",
7
+ "clean": "powershell Remove-Item lib/ -recurse",
8
+ "copy-files": "copyfiles -u 1 src/assets/*.* src/assets/ImageLibrary/*.* src/assets/thumbnails/*.* src/assets/IconsS4t/*.* src/assets/Metadata/*.* src/css/tm-sdkui.css lib/",
9
+ "tm-build": "npm run clean && tsc && npm run copy-files",
10
+ "tm-watch": "tsc -w",
11
+ "tm-publish": "npm publish --tag latest",
12
+ "tm-publish_wl": "npm publish",
13
+ "storybook": "storybook dev -p 6006",
14
+ "build-storybook": "storybook build"
15
+ },
16
+ "author": "TopConsult",
17
+ "license": "ISC",
18
+ "devDependencies": {
19
+ "@chromatic-com/storybook": "^5.1.2",
20
+ "@storybook/addon-docs": "^10.3.5",
21
+ "@storybook/addon-onboarding": "^10.3.5",
22
+ "@storybook/react-vite": "^10.3.5",
23
+ "@types/htmlparser2": "^3.10.7",
24
+ "@types/node": "^24.12.2",
25
+ "@types/react": "^18.3.3",
26
+ "@types/react-dom": "^18.3.3",
27
+ "copyfiles": "^2.4.1",
28
+ "esbuild": "^0.25.0",
29
+ "react": "^18.3.1",
30
+ "react-dom": "^18.3.1",
31
+ "storybook": "^10.3.5",
32
+ "typescript": "^5.9.3",
33
+ "vite": "^6.1.1"
34
+ },
35
+ "main": "dist/cjs/index.js",
36
+ "types": "./index.d.ts",
37
+ "module": "lib/esm/index.js",
38
+ "files": [
39
+ "dist",
40
+ "lib"
41
+ ],
42
+ "dependencies": {
43
+ "@topconsultnpm/sdk-ts": "6.21.0-dev1.5",
44
+ "buffer": "^6.0.3",
45
+ "devextreme": "^25.2.6",
46
+ "devextreme-react": "^25.2.6",
47
+ "exceljs": "^4.4.0",
48
+ "htmlparser2": "^10.0.0",
49
+ "pdfjs-dist": "5.4.296",
50
+ "react-pdf": "^10.3.0",
51
+ "react-router-dom": "^6.15.0",
52
+ "styled-components": "^6.1.1"
53
+ },
54
+ "overrides": {
55
+ "esbuild": "^0.25.0"
56
+ }
57
57
  }