@topconsultnpm/sdkui-react 6.21.0-dev1.2 → 6.21.0-dev1.21

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 (35) hide show
  1. package/lib/components/base/TMAreaManager.js +18 -3
  2. package/lib/components/base/TMPanel.js +1 -0
  3. package/lib/components/base/TMTreeView.d.ts +2 -1
  4. package/lib/components/base/TMTreeView.js +8 -3
  5. package/lib/components/choosers/TMUserChooser.js +3 -1
  6. package/lib/components/editors/TMFormulaEditor.js +3 -3
  7. package/lib/components/features/archive/TMArchive.js +1 -1
  8. package/lib/components/features/documents/TMDcmtForm.js +12 -8
  9. package/lib/components/features/documents/TMFileUploader.d.ts +1 -1
  10. package/lib/components/features/documents/TMFileUploader.js +3 -3
  11. package/lib/components/features/documents/TMMasterDetailDcmts.d.ts +27 -2
  12. package/lib/components/features/documents/TMMasterDetailDcmts.js +215 -20
  13. package/lib/components/features/documents/TMRelationViewer.d.ts +12 -1
  14. package/lib/components/features/documents/TMRelationViewer.js +49 -10
  15. package/lib/components/features/search/TMSavedQuerySelector.js +1 -1
  16. package/lib/components/features/search/TMSearch.d.ts +1 -0
  17. package/lib/components/features/search/TMSearch.js +2 -2
  18. package/lib/components/features/search/TMSearchResult.d.ts +1 -0
  19. package/lib/components/features/search/TMSearchResult.js +18 -4
  20. package/lib/components/features/search/TMViewHistoryDcmt.js +6 -0
  21. package/lib/components/features/workflow/diagram/DiagramItemForm.js +5 -1
  22. package/lib/components/features/workflow/diagram/WFDiagram.js +7 -1
  23. package/lib/components/features/workflow/diagram/xmlParser.js +13 -14
  24. package/lib/components/pages/TMPage.js +4 -2
  25. package/lib/components/query/TMQueryEditor.js +20 -1
  26. package/lib/helper/SDKUI_Globals.d.ts +2 -0
  27. package/lib/helper/checkinCheckoutManager.d.ts +1 -1
  28. package/lib/helper/checkinCheckoutManager.js +18 -4
  29. package/lib/hooks/useDcmtOperations.d.ts +1 -0
  30. package/lib/hooks/useDcmtOperations.js +75 -4
  31. package/lib/hooks/useDocumentOperations.d.ts +1 -0
  32. package/lib/hooks/useDocumentOperations.js +46 -12
  33. package/lib/hooks/useInputDialog.d.ts +2 -0
  34. package/lib/hooks/useInputDialog.js +34 -0
  35. package/package.json +55 -55
@@ -87,6 +87,12 @@ const TMViewHistoryDcmt = (props) => {
87
87
  IsSigned: row.IsSigned ? row.IsSigned.toString() === '1' : false,
88
88
  };
89
89
  });
90
+ // Sort by LastUpdateTime ascending
91
+ historyFileItems.sort((a, b) => {
92
+ const dateA = a.LastUpdateTime ? new Date(a.LastUpdateTime).getTime() : 0;
93
+ const dateB = b.LastUpdateTime ? new Date(b.LastUpdateTime).getTime() : 0;
94
+ return dateA - dateB;
95
+ });
90
96
  return historyFileItems;
91
97
  }
92
98
  return [];
@@ -70,7 +70,11 @@ const ButtonsContainer = styled.div `
70
70
  `;
71
71
  const SET_RULE_DATASOURCE = [
72
72
  { value: WorkItemSetRules.Ands_AND_Ors, display: "Ands_AND_Ors" },
73
- { value: WorkItemSetRules.Ands_OR_Ors, display: "Ands_OR_Ors" }
73
+ { value: WorkItemSetRules.Ands_OR_Ors, display: "Ands_OR_Ors" },
74
+ { value: WorkItemSetRules.Ands_AND_Ors_AssignModeOrs, display: "Ands_AND_Ors_AssignModeOrs" },
75
+ { value: WorkItemSetRules.Ands_OR_Ors_AssignModeOrs, display: "Ands_OR_Ors_AssignModeOrs" },
76
+ { value: WorkItemSetRules.Ands_AND_Ors_WaitForAllAnds, display: "Ands_AND_Ors_WaitForAllAnds" },
77
+ { value: WorkItemSetRules.Ands_OR_Ors_WaitForAllAnds, display: "Ands_OR_Ors_WaitForAllAnds" }
74
78
  ];
75
79
  const SEVERITY_DATASOURCE = [
76
80
  { value: Severities.Critical, display: "Critical" },
@@ -341,6 +341,7 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
341
341
  const isUndoingRedoing = useRef(false);
342
342
  const initialDiagramRef = useRef(null);
343
343
  const notifiedXmlRef = useRef(null);
344
+ const serializationGenRef = useRef(0);
344
345
  const svgRef = useRef(null);
345
346
  const containerRef = useRef(null);
346
347
  const [isDrawingConnection, setIsDrawingConnection] = useState(false);
@@ -430,10 +431,15 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
430
431
  setHistoryIndex(newHistory.length);
431
432
  }
432
433
  setWfDiagram(newDiagram);
434
+ const currentGen = ++serializationGenRef.current;
433
435
  (async () => {
434
436
  try {
435
437
  // await è necessario per attendere il risultato stringa
436
438
  const newXml = await serializeWfDiagramToXml(newDiagram);
439
+ // Ignora serializzazioni obsolete: se nel frattempo è partita una nuova serializzazione,
440
+ // questa è vecchia e non deve sovrascrivere il risultato più recente.
441
+ if (currentGen !== serializationGenRef.current)
442
+ return;
437
443
  notifiedXmlRef.current = newXml;
438
444
  // Chiama il callback per notificare TMWFEditor
439
445
  // L'invio dell'XML al genitore avviene solo a serializzazione completata.
@@ -449,7 +455,7 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
449
455
  catch (e) {
450
456
  TMExceptionBoxManager.show({ exception: e });
451
457
  }
452
- }, [wfDiagramHistory, historyIndex, isUndoingRedoing, setWfDiagramHistory, setHistoryIndex, setWfDiagram, isReadOnly]);
458
+ }, [wfDiagramHistory, historyIndex, isUndoingRedoing, setWfDiagramHistory, setHistoryIndex, setWfDiagram, isReadOnly, onDiagramChange]);
453
459
  const handleUndo = useCallback(() => {
454
460
  if (isReadOnly)
455
461
  return;
@@ -67,14 +67,13 @@ export const getSeveritiesNumber = (severity) => {
67
67
  };
68
68
  export const getWorkItemSetRulesNumber = (setRule) => {
69
69
  switch (setRule) {
70
- case WorkItemSetRules.Ands_AND_Ors:
71
- return 0;
72
- case WorkItemSetRules.Ands_OR_Ors:
73
- return 1;
74
- case WorkItemSetRules.Custom:
75
- return 2;
76
- default:
77
- return 0;
70
+ case WorkItemSetRules.Ands_AND_Ors: return 0;
71
+ case WorkItemSetRules.Ands_OR_Ors: return 1;
72
+ case WorkItemSetRules.Ands_AND_Ors_AssignModeOrs: return 2;
73
+ case WorkItemSetRules.Ands_OR_Ors_AssignModeOrs: return 3;
74
+ case WorkItemSetRules.Ands_AND_Ors_WaitForAllAnds: return 4;
75
+ case WorkItemSetRules.Ands_OR_Ors_WaitForAllAnds: return 5;
76
+ default: return 0;
78
77
  }
79
78
  };
80
79
  export const getWFAppTypesNumber = (appType) => {
@@ -147,12 +146,12 @@ const mapSeverity = (severityValue) => {
147
146
  // Funzione helper per mappare i valori numerici di WorkItemSetRules
148
147
  const mapWorkItemSetRules = (ruleValue) => {
149
148
  switch (ruleValue) {
150
- case 0:
151
- return WorkItemSetRules.Ands_AND_Ors;
152
- case 1:
153
- return WorkItemSetRules.Ands_OR_Ors;
154
- case 2:
155
- return WorkItemSetRules.Custom;
149
+ case 0: return WorkItemSetRules.Ands_AND_Ors;
150
+ case 1: return WorkItemSetRules.Ands_OR_Ors;
151
+ case 2: return WorkItemSetRules.Ands_AND_Ors_AssignModeOrs;
152
+ case 3: return WorkItemSetRules.Ands_OR_Ors_AssignModeOrs;
153
+ case 4: return WorkItemSetRules.Ands_AND_Ors_WaitForAllAnds;
154
+ case 5: return WorkItemSetRules.Ands_OR_Ors_WaitForAllAnds;
156
155
  default:
157
156
  console.warn(`Valore WorkItemSetRules sconosciuto: ${ruleValue}. Ritorno WorkItemSetRules.Ands_AND_Ors.`);
158
157
  return WorkItemSetRules.Ands_AND_Ors;
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React, { useState, useEffect } from "react";
3
3
  import { SDK_Globals, ObjectClasses, ResultTypes } from "@topconsultnpm/sdk-ts";
4
4
  import DataGrid, { Column, GroupPanel, Grouping, HeaderFilter, LoadPanel, Pager, Paging, Scrolling, SearchPanel, Selection } from "devextreme-react/data-grid";
@@ -215,7 +215,9 @@ const TMPage = ({ id, objClass = ObjectClasses.None, listDisabled = false, lastR
215
215
  return;
216
216
  setSelectedItems([row.data]);
217
217
  setShowList(false);
218
- }, showColumnLines: Number(SDKUI_Globals.userSettings?.themeSettings.gridSettings.showColumnLines) === 1, showRowLines: Number(SDKUI_Globals.userSettings?.themeSettings.gridSettings.showRowLines) === 1, onSelectionChanged: (e) => { setSelectedItems(e.selectedRowsData); onSelectionChanged?.(e.selectedRowsData); }, children: [_jsx(GroupPanel, { visible: !!(deviceType !== DeviceType.MOBILE && showAllColumns) }), _jsx(SearchPanel, { visible: false }), _jsx(Grouping, { autoExpandAll: false }), _jsx(HeaderFilter, { visible: true }), _jsx(Selection, { mode: "multiple", showCheckBoxesMode: "onClick", selectAllMode: 'allPages' }), _jsx(Scrolling, { mode: "standard", useNative: Number(SDKUI_Globals.userSettings?.themeSettings.gridSettings.useNativeScrollbar) === 1 }), _jsx(Paging, { pageSize: 25 }), _jsx(Pager, { visible: true, showInfo: true, showNavigationButtons: true }), _jsx(LoadPanel, { enabled: true }), _jsx(Column, { width: 20, cellRender: cellRenderObjectIcon }), _jsx(Column, { width: 'auto', visible: showId, dataField: "id", caption: "ID" }), _jsx(Column, { width: 250, dataField: "name", caption: SDKUI_Localizator.Name, sortOrder: "asc" }), _jsx(Column, { width: 250, visible: showAllColumns, dataField: "description", caption: SDKUI_Localizator.Description }), customColumns?.map((item, index) => { return React.cloneElement(item, { key: index, visible: showAllColumns }); }), _jsx(Column, { width: 'auto', visible: showAllColumns, dataField: "ownerID", caption: SDKUI_Localizator.OwnerID }), _jsx(Column, { width: 'auto', visible: showAllColumns, dataField: "ownerName", caption: SDKUI_Localizator.OwnerName }), _jsx(Column, { width: 'auto', dataType: "date", format: Globalization.getDateDisplayFormat(), visible: showAllColumns, dataField: "creationTime", caption: SDKUI_Localizator.CreationTime }), _jsx(Column, { width: 'auto', dataType: "date", format: Globalization.getDateDisplayFormat(), visible: showAllColumns, dataField: "lastUpdateTime", caption: SDKUI_Localizator.LastUpdateTime })] })] }), detailInsteadOfContent ??
218
+ }, showColumnLines: Number(SDKUI_Globals.userSettings?.themeSettings.gridSettings.showColumnLines) === 1, showRowLines: Number(SDKUI_Globals.userSettings?.themeSettings.gridSettings.showRowLines) === 1, onSelectionChanged: (e) => { setSelectedItems(e.selectedRowsData); onSelectionChanged?.(e.selectedRowsData); }, children: [_jsx(GroupPanel, { visible: !!(deviceType !== DeviceType.MOBILE && showAllColumns) }), _jsx(SearchPanel, { visible: false }), _jsx(Grouping, { autoExpandAll: false }), _jsx(HeaderFilter, { visible: true }), _jsx(Selection, { mode: "multiple", showCheckBoxesMode: "onClick", selectAllMode: 'allPages' }), _jsx(Scrolling, { mode: "standard", useNative: Number(SDKUI_Globals.userSettings?.themeSettings.gridSettings.useNativeScrollbar) === 1 }), _jsx(Paging, { pageSize: 25 }), _jsx(Pager, { visible: true, showInfo: true, showNavigationButtons: true }), _jsx(LoadPanel, { enabled: true }), _jsx(Column, { width: 20, cellRender: cellRenderObjectIcon }), _jsx(Column, { width: 'auto', visible: showId, dataField: "id", caption: "ID" }), _jsx(Column, { width: 250, dataField: "name", caption: SDKUI_Localizator.Name, sortOrder: "asc" }), objClass == ObjectClasses.User ?
219
+ _jsxs(_Fragment, { children: [_jsx(Column, { width: 'auto', dataField: "type", caption: SDKUI_Localizator.Type }), _jsx(Column, { width: 'auto', dataField: "fn", caption: SDKUI_Localizator.User_FirstName }), _jsx(Column, { width: 'auto', dataField: "ln", caption: SDKUI_Localizator.User_LastName })] })
220
+ : _jsx(_Fragment, {}), _jsx(Column, { width: 250, visible: objClass == ObjectClasses.User ? true : showAllColumns, dataField: "description", caption: SDKUI_Localizator.Description }), customColumns?.map((item, index) => { return React.cloneElement(item, { key: index, visible: showAllColumns }); }), _jsx(Column, { width: 'auto', visible: showAllColumns, dataField: "ownerID", caption: SDKUI_Localizator.OwnerID }), _jsx(Column, { width: 'auto', visible: showAllColumns, dataField: "ownerName", caption: SDKUI_Localizator.OwnerName }), _jsx(Column, { width: 'auto', dataType: "date", format: Globalization.getDateDisplayFormat(), visible: showAllColumns, dataField: "creationTime", caption: SDKUI_Localizator.CreationTime }), _jsx(Column, { width: 'auto', dataType: "date", format: Globalization.getDateDisplayFormat(), visible: showAllColumns, dataField: "lastUpdateTime", caption: SDKUI_Localizator.LastUpdateTime })] })] }), detailInsteadOfContent ??
219
221
  _jsx(TMLayoutItem, { children: selectedItems.length == 1 || formMode == FormModes.Create || formMode == FormModes.Duplicate ?
220
222
  _jsx(TMToolbarCard, { onBack: deviceType === DeviceType.MOBILE ? () => setShowList(true) : undefined, title: calcSaveFormTitle(objName, formMode, selectedItems.length == 0 ? -1 : selectedItems[0].id, detailTitlePathKeys), children: getDetailFormWithProps() })
221
223
  :
@@ -703,7 +703,26 @@ const TMQueryEditor = ({ formMode, inputData, onQDChanged, isExpertMode, showDis
703
703
  }
704
704
  };
705
705
  // #endregion
706
- return (_jsxs(_Fragment, { children: [_jsxs(TMApplyForm, { isModal: false, formMode: formMode, isModified: calcIsModified(formData, formDataOrig), exception: exception, validationItems: validationItems, hasNavigation: false, customToolbarElements: _jsxs(_Fragment, { children: [_jsx(TMButton, { btnStyle: 'toolbar', caption: SDKUI_Localizator.Search, color: 'tertiary', icon: _jsx(IconSearch, {}), disabled: errorsCount > 0, onClick: async () => await onSearchAsync(formData) }), _jsx(TMButton, { btnStyle: 'toolbar', caption: SDKUI_Localizator.Count, icon: _jsx(IconCount, {}), disabled: errorsCount > 0, onClick: () => getQueryCountAsync(formData, true) }), SDK_Globals.tmSession?.SessionDescr?.appModuleID == AppModules.SURFER && _jsx(TMButton, { caption: "Passa ad archiviazione", icon: _jsx(IconArchiveDoc, {}), btnStyle: 'toolbar', fontSize: '1.3rem', onClick: () => { ShowAlert({ message: "TODO Passa ad archiviazione", mode: 'info', title: `${"TODO"}`, duration: 3000 }); } }), SDK_Globals.tmSession?.SessionDescr?.appModuleID == AppModules.SURFER && _jsx(TMButton, { caption: "Vai a risultato", icon: _jsx(IconArrowRight, {}), btnStyle: 'toolbar', fontSize: '1.3rem', onClick: () => { ShowAlert({ message: "TODO Vai a risultato", mode: 'info', title: `${"TODO"}`, duration: 3000 }); } })] }), showToolbar: showToolbar, showApply: showApply, showUndo: showUndo, showBack: showBack, onApply: () => applyData(), onClose: () => onClose?.(), onUndo: () => setFormData(formDataOrig), children: [_jsxs(Accordion, { elementAttr: { class: 'tm-query-dx-accordion' }, height: height, multiple: true, collapsible: true, repaintChangesOnly: true, deferRendering: false, animationDuration: 0, onContentReady: (e) => {
706
+ const getQueryCountLocalAsync = async (qd, showSpinner) => {
707
+ if (IsParametricQuery(qd)) {
708
+ const qdParams = await confirmQueryParams(qd, lastQdParams);
709
+ setLastQdParams(qdParams);
710
+ if (!qdParams || qdParams.length <= 0)
711
+ return;
712
+ for (const qpd of qdParams) {
713
+ let wi = qd.where?.find(o => o.value1 == qpd.name);
714
+ if (wi)
715
+ wi.value1 = wi.value1?.replace(wi.value1, !qpd.value ? '' : qpd.value.toString());
716
+ else {
717
+ wi = qd.where?.find(o => o.value2 == qpd.name);
718
+ if (wi)
719
+ wi.value2 = wi.value2?.replace(wi.value2, !qpd.value ? '' : qpd.value.toString());
720
+ }
721
+ }
722
+ }
723
+ await getQueryCountAsync(qd, showSpinner);
724
+ };
725
+ return (_jsxs(_Fragment, { children: [_jsxs(TMApplyForm, { isModal: false, formMode: formMode, isModified: calcIsModified(formData, formDataOrig), exception: exception, validationItems: validationItems, hasNavigation: false, customToolbarElements: _jsxs(_Fragment, { children: [_jsx(TMButton, { btnStyle: 'toolbar', caption: SDKUI_Localizator.Search, color: 'tertiary', icon: _jsx(IconSearch, {}), disabled: errorsCount > 0, onClick: async () => await onSearchAsync(formData) }), _jsx(TMButton, { btnStyle: 'toolbar', caption: SDKUI_Localizator.Count, icon: _jsx(IconCount, {}), disabled: errorsCount > 0, onClick: () => getQueryCountLocalAsync(formData, true) }), SDK_Globals.tmSession?.SessionDescr?.appModuleID == AppModules.SURFER && _jsx(TMButton, { caption: "Passa ad archiviazione", icon: _jsx(IconArchiveDoc, {}), btnStyle: 'toolbar', fontSize: '1.3rem', onClick: () => { ShowAlert({ message: "TODO Passa ad archiviazione", mode: 'info', title: `${"TODO"}`, duration: 3000 }); } }), SDK_Globals.tmSession?.SessionDescr?.appModuleID == AppModules.SURFER && _jsx(TMButton, { caption: "Vai a risultato", icon: _jsx(IconArrowRight, {}), btnStyle: 'toolbar', fontSize: '1.3rem', onClick: () => { ShowAlert({ message: "TODO Vai a risultato", mode: 'info', title: `${"TODO"}`, duration: 3000 }); } })] }), showToolbar: showToolbar, showApply: showApply, showUndo: showUndo, showBack: showBack, onApply: () => applyData(), onClose: () => onClose?.(), onUndo: () => setFormData(formDataOrig), children: [_jsxs(Accordion, { elementAttr: { class: 'tm-query-dx-accordion' }, height: height, multiple: true, collapsible: true, repaintChangesOnly: true, deferRendering: false, animationDuration: 0, onContentReady: (e) => {
707
726
  let items = e.component.option("items");
708
727
  if (items && items.length > 0) {
709
728
  for (let i = 0; i < items.length; i++) {
@@ -123,4 +123,6 @@ export declare class DcmtFormSettings {
123
123
  }
124
124
  export declare class SDKUI_Globals {
125
125
  static userSettings: UserSettings;
126
+ /** Global handler for scanner requests. Set by the host app (e.g. surfer) to open the scanner UI. */
127
+ static scanRequestHandler?: (mode: 'new' | 'edit', onFileScanned: (file: File) => void, onCancel: () => void, existingFile?: File) => void;
126
128
  }
@@ -22,7 +22,7 @@ export interface CheckoutInfo {
22
22
  checkoutFolder: string;
23
23
  checkoutName: string;
24
24
  }
25
- interface CheckoutStatusResult {
25
+ export interface CheckoutStatusResult {
26
26
  isCheckedOut: boolean;
27
27
  mode: 'editMode' | 'lockMode' | '';
28
28
  version: number;
@@ -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
  };
@@ -86,6 +86,7 @@ export interface OperationCallbacks {
86
86
  openWGsCopyMoveForm?: (mode: "copyToWgDraft" | "copyToWgArchivedDoc", dcmtTypeDescriptor: DcmtTypeDescriptor, documents: Array<DcmtInfo>) => void;
87
87
  onOpenS4TViewerRequest?: (dcmtInfo: Array<DcmtInfo>, refreshDocumentPreview?: () => Promise<void>) => void;
88
88
  onOpenPdfEditorRequest?: (dcmtInfo: Array<DcmtInfo>, refreshDocumentPreview?: () => Promise<void>) => void;
89
+ openFileUploaderPdfEditor?: (fromDTD?: DcmtTypeDescriptor, file?: File | null, handleFile?: (file: File) => void) => void;
89
90
  onTaskCreateRequest?: (taskContext: TaskContext, onTaskCreated?: (task?: TaskDescriptor) => void) => void;
90
91
  openTaskFormHandler?: (onTaskCreated?: (task?: TaskDescriptor) => void) => void;
91
92
  }
@@ -93,7 +93,7 @@ export const useDocumentOperations = (props) => {
93
93
  // Navigation
94
94
  canNavigateHandler, onNavigateHandler, handleNavigateToWGs, handleNavigateToDossiers, onReferenceClick,
95
95
  // Document forms/operations
96
- openAddDocumentForm, openCommentFormCallback, onFileOpened, passToArchiveCallback, openWGsCopyMoveForm, onOpenS4TViewerRequest, onOpenPdfEditorRequest,
96
+ openAddDocumentForm, openCommentFormCallback, onFileOpened, passToArchiveCallback, openWGsCopyMoveForm, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor,
97
97
  // Task related
98
98
  onTaskCreateRequest, openTaskFormHandler, } = callbacks;
99
99
  // Force recalculation of selectedDcmtInfos when refreshOperationsTrigger changes (e.g., after file substitution where FILEEXT may change)
@@ -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);
@@ -820,7 +821,14 @@ export const useDocumentOperations = (props) => {
820
821
  try {
821
822
  TMSpinner.show({ description: `${SDKUI_Localizator.Loading}...` });
822
823
  const msg = await SDK_Globals.tmSession?.NewSearchEngine().FreeSearchGetDcmtInfoAsync(dcmt.TID, dcmt.DID);
823
- TMMessageBoxManager.show({ buttons: [ButtonNames.OK], message: msg, title: SDKUI_Localizator.IndexingInformation });
824
+ TMMessageBoxManager.show({
825
+ buttons: [ButtonNames.OK],
826
+ showToppy: false,
827
+ resizable: true,
828
+ initialWidth: !isMobile ? '700px' : undefined,
829
+ message: msg,
830
+ title: SDKUI_Localizator.IndexingInformation
831
+ });
824
832
  }
825
833
  catch (e) {
826
834
  TMExceptionBoxManager.show({ exception: e });
@@ -1044,6 +1052,25 @@ export const useDocumentOperations = (props) => {
1044
1052
  return items.sort((a, b) => a.name.localeCompare(b.name));
1045
1053
  };
1046
1054
  const getDcmtFormMenuItems = () => {
1055
+ return [
1056
+ {
1057
+ id: 'doc',
1058
+ icon: _jsx(IconFileDots, {}),
1059
+ name: !isMobile ? SDKUI_Localizator.DocumentOperations : SDKUI_Localizator.Documents,
1060
+ disabled: isDisabledForSingleRow() && isDisabledForMultiRow(),
1061
+ submenu: [
1062
+ addToFavoriteOperation(),
1063
+ downloadFileMenuItem(),
1064
+ downloadXMLAttachmentsMenuItem(),
1065
+ ]
1066
+ },
1067
+ signatureMenuItem(),
1068
+ checkinMenuItem(),
1069
+ ...(allowRelations && inputDcmtFormLayoutMode === LayoutModes.Update ? [relationsMenuItem()] : []),
1070
+ ...((inputDcmtFormLayoutMode === LayoutModes.Update) ? [fullTextSearchMenuItem()] : []),
1071
+ ];
1072
+ };
1073
+ const getMasterDetailMenuItems = () => {
1047
1074
  return [
1048
1075
  {
1049
1076
  id: 'doc',
@@ -1052,15 +1079,19 @@ export const useDocumentOperations = (props) => {
1052
1079
  disabled: isDisabledForSingleRow() && isDisabledForMultiRow(),
1053
1080
  submenu: [
1054
1081
  ...(inputDcmtFormLayoutMode === LayoutModes.Update ? [addToFavoriteOperation()] : []),
1055
- ...((onTaskCreateRequest && inputDcmtFormLayoutMode === LayoutModes.Update && SDK_Globals.tmSession?.SessionDescr?.appModuleID === AppModules.SURFER) ? [createContextualTaskMenuItem()] : []),
1082
+ addReplaceFileOperation(),
1083
+ openFormOperation(),
1084
+ deletetionMenuItem(),
1085
+ fileCheckMenuItem(),
1086
+ fileConversionsMenuItem(),
1087
+ ...(SDK_Globals.tmSession?.SessionDescr?.appModuleID === AppModules.SURFER ? [createContextualTaskMenuItem()] : []),
1056
1088
  downloadFileMenuItem(),
1057
1089
  downloadXMLAttachmentsMenuItem(),
1058
- ...(selectedDcmtInfos.length > 0 && isPdfEditorAvailable(dtd, selectedDcmtInfos[0]?.FILEEXT) && onOpenPdfEditorRequest ? [pdfEditorMenuItem(onOpenPdfEditorRequest)] : []),
1090
+ ...(selectedDcmtInfos.length > 0 && isPdfEditorAvailable(dtd, selectedDcmtInfos[0]?.FILEEXT) && onOpenPdfEditorRequest ? [pdfEditorMenuItem(onOpenPdfEditorRequest)] : [])
1059
1091
  ]
1060
1092
  },
1061
1093
  signatureMenuItem(),
1062
1094
  checkinMenuItem(),
1063
- ...(allowRelations && inputDcmtFormLayoutMode === LayoutModes.Update ? [relationsMenuItem()] : []),
1064
1095
  ...((inputDcmtFormLayoutMode === LayoutModes.Update) ? [fullTextSearchMenuItem()] : []),
1065
1096
  ];
1066
1097
  };
@@ -1071,6 +1102,8 @@ export const useDocumentOperations = (props) => {
1071
1102
  return getDcmtFormMenuItems();
1072
1103
  case SearchResultContext.ARCHIVED_WORKGROUP:
1073
1104
  return getArchivedWorkgroupMenuItems();
1105
+ case SearchResultContext.MASTER_DETAIL:
1106
+ return getMasterDetailMenuItems();
1074
1107
  default:
1075
1108
  return getDefaultMenuItems();
1076
1109
  }
@@ -1084,15 +1117,15 @@ export const useDocumentOperations = (props) => {
1084
1117
  };
1085
1118
  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;
1086
1119
  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) &&
1087
- _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: () => { setIsOpenDcmtForm(false); onDcmtFormOpenChange(false, LayoutModes.Update); }, 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: {
1120
+ _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: {
1088
1121
  onRefreshSearchAsyncDatagrid,
1089
1122
  onRefreshDataRowsAsync,
1090
1123
  refreshFocusedDataRowAsync,
1091
1124
  onRefreshBlogDatagrid,
1092
1125
  onRefreshPreviewDatagrid
1093
1126
  } })) }), (showHistory && dtd && selectedDcmtInfos.length > 0) && _jsx(TMViewHistoryDcmt, { fromDTD: dtd, deviceType: deviceType, inputDcmt: selectedDcmtInfos[0], onClose: hideHistoryCallback, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), (commentFormState.show && selectedDcmtInfos.length > 0) && _jsx(TMBlogCommentForm, { context: { engine: 'SearchEngine', object: { tid: selectedDcmtInfos[0].TID, did: selectedDcmtInfos[0].DID } }, onClose: hideCommentFormCallback, refreshCallback: onRefreshBlog, participants: [], showAttachmentsSection: true, allArchivedDocumentsFileItems: convertSearchResultDescriptorToFileItems(currentSearchResults ?? []), isCommentRequired: commentFormState.isRequired, removeAndEditAttachment: commentFormState.removeAndEditAttachment, selectedAttachmentDid: [Number(selectedDcmtInfos[0].DID)] }), (showCheckoutInformationForm && dtd && selectedDcmtInfos.length > 0) &&
1094
- _jsx(TMDcmtCheckoutInfoForm, { dtdName: dtd.name ?? SDKUI_Localizator.SearchResult, selectedDcmtOrFocused: selectedDcmtInfos[0], onClose: hideCheckoutInformationFormCallback }), _jsx(StyledMultiViewPanel, { "$isVisible": isOpenDetails, children: isOpenDetails && _jsx(TMMasterDetailDcmts, { deviceType: deviceType, isForMaster: false, inputDcmts: selectedDcmtInfos, allowNavigation: selectedDcmtInfos.length === 1, canNext: canNavigateHandler ? canNavigateHandler('next') : false, canPrev: canNavigateHandler ? canNavigateHandler('prev') : false, onNext: () => onNavigateHandler && onNavigateHandler('next'), onPrev: () => onNavigateHandler && onNavigateHandler('prev'), onBack: () => setIsOpenDetails(false), allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }) }), _jsxs(StyledMultiViewPanel, { "$isVisible": isOpenMaster, children: [isOpenMaster && _jsx(TMMasterDetailDcmts, { deviceType: deviceType, inputDcmts: selectedDcmtInfos, isForMaster: true, allowNavigation: selectedDcmtInfos.length === 1, canNext: canNavigateHandler ? canNavigateHandler('next') : false, canPrev: canNavigateHandler ? canNavigateHandler('prev') : false, onNext: () => onNavigateHandler && onNavigateHandler('next'), onPrev: () => onNavigateHandler && onNavigateHandler('prev'), onBack: () => setIsOpenMaster(false), appendMasterDcmts: handleAddItem, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), secondaryMasterDcmts.length > 0 && secondaryMasterDcmts.map((dcmt, index) => {
1095
- return (_jsx(StyledModalContainer, { style: { backgroundColor: 'white' }, children: _jsx(TMMasterDetailDcmts, { deviceType: deviceType, inputDcmts: [dcmt], isForMaster: true, allowNavigation: false, onBack: () => handleRemoveItem(dcmt.TID, dcmt.DID), appendMasterDcmts: handleAddItem, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }) }, `${index}-${dcmt.DID}`));
1127
+ _jsx(TMDcmtCheckoutInfoForm, { dtdName: dtd.name ?? SDKUI_Localizator.SearchResult, selectedDcmtOrFocused: selectedDcmtInfos[0], onClose: hideCheckoutInformationFormCallback }), _jsx(StyledMultiViewPanel, { "$isVisible": isOpenDetails, children: isOpenDetails && _jsx(TMMasterDetailDcmts, { deviceType: deviceType, isForMaster: false, inputDcmts: selectedDcmtInfos, allowNavigation: selectedDcmtInfos.length === 1, canNext: canNavigateHandler ? canNavigateHandler('next') : false, canPrev: canNavigateHandler ? canNavigateHandler('prev') : false, onNext: () => onNavigateHandler && onNavigateHandler('next'), onPrev: () => onNavigateHandler && onNavigateHandler('prev'), onBack: () => setIsOpenDetails(false), allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, editPdfForm: editPdfForm, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onOpenPdfEditorRequest: onOpenPdfEditorRequest, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, onTaskCreateRequest: onTaskCreateRequest, datagridUtility: datagridUtility, dcmtUtility: dcmtUtility }) }), _jsxs(StyledMultiViewPanel, { "$isVisible": isOpenMaster, children: [isOpenMaster && _jsx(TMMasterDetailDcmts, { deviceType: deviceType, inputDcmts: selectedDcmtInfos, isForMaster: true, allowNavigation: selectedDcmtInfos.length === 1, canNext: canNavigateHandler ? canNavigateHandler('next') : false, canPrev: canNavigateHandler ? canNavigateHandler('prev') : false, onNext: () => onNavigateHandler && onNavigateHandler('next'), onPrev: () => onNavigateHandler && onNavigateHandler('prev'), onBack: () => setIsOpenMaster(false), appendMasterDcmts: handleAddItem, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, editPdfForm: editPdfForm, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onOpenPdfEditorRequest: onOpenPdfEditorRequest, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, onTaskCreateRequest: onTaskCreateRequest, datagridUtility: datagridUtility, dcmtUtility: dcmtUtility }), secondaryMasterDcmts.length > 0 && secondaryMasterDcmts.map((dcmt, index) => {
1128
+ return (_jsx(StyledModalContainer, { style: { backgroundColor: 'white' }, children: _jsx(TMMasterDetailDcmts, { deviceType: deviceType, inputDcmts: [dcmt], isForMaster: true, allowNavigation: false, onBack: () => handleRemoveItem(dcmt.TID, dcmt.DID), appendMasterDcmts: handleAddItem, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, editPdfForm: editPdfForm, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onOpenPdfEditorRequest: onOpenPdfEditorRequest, onTaskCreateRequest: onTaskCreateRequest, datagridUtility: datagridUtility, dcmtUtility: dcmtUtility }) }, `${index}-${dcmt.DID}`));
1096
1129
  })] }), isOpenArchiveRelationForm && _jsx(TMDcmtForm, { isModal: true, titleModal: SDKUI_Localizator.Archive + ' - ' + (archiveType === 'detail' ? SDKUI_Localizator.DcmtsDetail : SDKUI_Localizator.DcmtsMaster), TID: archiveRelatedDcmtFormTID, layoutMode: LayoutModes.Ark, inputMids: archiveRelatedDcmtFormMids, showBackButton: false, allowButtonsRefs: false, onClose: () => {
1097
1130
  setIsOpenArchiveRelationForm(false);
1098
1131
  setArchiveType(undefined);
@@ -1104,7 +1137,7 @@ export const useDocumentOperations = (props) => {
1104
1137
  setArchiveRelatedDcmtFormTID(undefined);
1105
1138
  setArchiveRelatedDcmtFormMids([]);
1106
1139
  await onRefreshSearchAsyncDatagrid?.();
1107
- }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, showDcmtFormSidebar: showDcmtFormSidebar }), showRelatedDcmtsChooser &&
1140
+ }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, showDcmtFormSidebar: showDcmtFormSidebar, openFileUploaderPdfEditor: openFileUploaderPdfEditor }), showRelatedDcmtsChooser &&
1108
1141
  _jsx(TMChooserForm, { dataSource: relatedDcmtsChooserDataSource, onChoose: async (selectedRelation) => {
1109
1142
  try {
1110
1143
  setShowRelatedDcmtsChooser(false);
@@ -1150,7 +1183,7 @@ export const useDocumentOperations = (props) => {
1150
1183
  updateBatchUpdateForm(false);
1151
1184
  setIsModifiedBatchUpdate(false);
1152
1185
  await onRefreshDataRowsAsync?.();
1153
- }, 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) })] }));
1186
+ }, 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) })] }));
1154
1187
  return {
1155
1188
  operationItems: operationItems(),
1156
1189
  renderFloatingBar,
@@ -1203,6 +1236,7 @@ export const useDocumentOperations = (props) => {
1203
1236
  removeDcmtsFileCache,
1204
1237
  isDcmtFileInCache,
1205
1238
  runOperationAsync,
1239
+ FileSourceDialog,
1206
1240
  },
1207
1241
  relatedDocumentsInfo: {
1208
1242
  // Data
@@ -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
+ };