@topconsultnpm/sdkui-react 6.22.0-t1 → 6.22.0-t2

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 (159) hide show
  1. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +1 -1
  2. package/lib/components/NewComponents/ContextMenu/styles.d.ts +45 -43
  3. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +1 -1
  4. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +67 -60
  5. package/lib/components/base/Styled.d.ts +92 -76
  6. package/lib/components/base/TMButton.d.ts +13 -0
  7. package/lib/components/base/TMButton.js +137 -5
  8. package/lib/components/base/TMDataGrid.d.ts +2 -0
  9. package/lib/components/base/TMDataGrid.js +260 -8
  10. package/lib/components/base/TMDataGridExportForm.js +39 -30
  11. package/lib/components/base/TMEditorBase.d.ts +2 -0
  12. package/lib/components/base/TMFileManager.js +5 -3
  13. package/lib/components/base/TMFileManagerDataGridView.js +11 -2
  14. package/lib/components/base/TMFileManagerThumbnailItems.js +19 -9
  15. package/lib/components/base/TMFileManagerUtils.d.ts +6 -6
  16. package/lib/components/base/TMFileManagerUtils.js +37 -1
  17. package/lib/components/base/TMModal.d.ts +11 -0
  18. package/lib/components/base/TMModal.js +47 -13
  19. package/lib/components/base/TMPanel.d.ts +6 -0
  20. package/lib/components/base/TMPanel.js +138 -25
  21. package/lib/components/base/TMPopUp.js +3 -0
  22. package/lib/components/base/TMTooltip.d.ts +2 -1
  23. package/lib/components/base/TMTooltip.js +24 -8
  24. package/lib/components/base/TMTreeView.d.ts +13 -7
  25. package/lib/components/base/TMTreeView.js +108 -67
  26. package/lib/components/choosers/TMDcmtTypeChooser.js +4 -3
  27. package/lib/components/choosers/TMDistinctValues.d.ts +9 -7
  28. package/lib/components/choosers/TMDistinctValues.js +149 -142
  29. package/lib/components/choosers/TMMetadataChooser.js +1 -1
  30. package/lib/components/choosers/TMQuickSearchInfo.d.ts +13 -0
  31. package/lib/components/choosers/TMQuickSearchInfo.js +279 -0
  32. package/lib/components/choosers/TMQuickSearchSettingsForm.d.ts +16 -0
  33. package/lib/components/choosers/TMQuickSearchSettingsForm.js +94 -0
  34. package/lib/components/choosers/TMSelectedValuesSummary.d.ts +13 -0
  35. package/lib/components/choosers/TMSelectedValuesSummary.js +91 -0
  36. package/lib/components/editors/TMDateBox.d.ts +16 -1
  37. package/lib/components/editors/TMDateBox.js +90 -22
  38. package/lib/components/editors/TMDropDown.d.ts +3 -0
  39. package/lib/components/editors/TMDropDown.js +197 -5
  40. package/lib/components/editors/TMEditorStyled.d.ts +20 -42
  41. package/lib/components/editors/TMMetadataEditor.d.ts +5 -1
  42. package/lib/components/editors/TMMetadataEditor.js +27 -23
  43. package/lib/components/editors/TMTextArea.d.ts +1 -0
  44. package/lib/components/editors/TMTextArea.js +23 -15
  45. package/lib/components/editors/TMTextBox.d.ts +2 -0
  46. package/lib/components/editors/TMTextBox.js +30 -19
  47. package/lib/components/features/archive/TMArchive.js +17 -3
  48. package/lib/components/features/documents/TMBatchUpdateForm.js +19 -5
  49. package/lib/components/features/documents/TMDcmtBlog.d.ts +3 -0
  50. package/lib/components/features/documents/TMDcmtBlog.js +4 -4
  51. package/lib/components/features/documents/TMDcmtForm.d.ts +7 -0
  52. package/lib/components/features/documents/TMDcmtForm.js +232 -53
  53. package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +11 -0
  54. package/lib/components/features/documents/TMDcmtFormActionButtons.js +77 -7
  55. package/lib/components/features/documents/TMDcmtIcon.js +5 -3
  56. package/lib/components/features/documents/TMDcmtPreview.d.ts +7 -5
  57. package/lib/components/features/documents/TMDcmtPreview.js +10 -6
  58. package/lib/components/features/documents/TMMasterDetailDcmts.js +95 -33
  59. package/lib/components/features/documents/TMMasterInfoFields.d.ts +20 -0
  60. package/lib/components/features/documents/TMMasterInfoFields.js +186 -0
  61. package/lib/components/features/documents/TMMergeToPdfForm.d.ts +1 -2
  62. package/lib/components/features/documents/TMMergeToPdfForm.js +30 -5
  63. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +46 -0
  64. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +323 -0
  65. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +370 -0
  66. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.js +283 -0
  67. package/lib/components/features/documents/TMRelationViewer.d.ts +14 -1
  68. package/lib/components/features/documents/TMRelationViewer.js +82 -52
  69. package/lib/components/features/search/TMSearch.js +103 -24
  70. package/lib/components/features/search/TMSearchQueryEditor.js +5 -3
  71. package/lib/components/features/search/TMSearchQueryPanel.d.ts +14 -4
  72. package/lib/components/features/search/TMSearchQueryPanel.js +152 -57
  73. package/lib/components/features/search/TMSearchResult.d.ts +16 -0
  74. package/lib/components/features/search/TMSearchResult.js +438 -145
  75. package/lib/components/features/search/TMTreeSelector.js +109 -64
  76. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +10 -0
  77. package/lib/components/features/workflow/TMWorkflowPopup.js +8 -4
  78. package/lib/components/features/workflow/diagram/WorkitemRecipientsEditor.d.ts +3 -1
  79. package/lib/components/forms/Login/ChangePasswordInputs.d.ts +3 -1
  80. package/lib/components/grids/TMBlogAttachments.js +13 -2
  81. package/lib/components/grids/TMBlogHeader.js +5 -1
  82. package/lib/components/grids/TMBlogsPost.d.ts +2 -0
  83. package/lib/components/grids/TMBlogsPost.js +31 -4
  84. package/lib/components/grids/TMBlogsPostUtils.d.ts +1 -0
  85. package/lib/components/grids/TMBlogsPostUtils.js +14 -3
  86. package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +1 -0
  87. package/lib/components/layout/panelManager/TMPanelManagerContainer.js +24 -14
  88. package/lib/components/layout/panelManager/TMPanelManagerContext.js +68 -93
  89. package/lib/components/layout/panelManager/TMPanelManagerToolbar.d.ts +4 -5
  90. package/lib/components/layout/panelManager/TMPanelWrapper.js +2 -2
  91. package/lib/components/layout/panelManager/types.d.ts +3 -0
  92. package/lib/components/layout/panelManager/utils.js +13 -11
  93. package/lib/components/query/TMQueryEditor.d.ts +14 -10
  94. package/lib/components/sidebar/TMCommandsPanel.d.ts +4 -4
  95. package/lib/components/sidebar/TMHeader.js +30 -20
  96. package/lib/components/viewers/TMMidViewer.js +5 -2
  97. package/lib/components/viewers/TMTidViewer.js +86 -25
  98. package/lib/css/tm-sdkui.css +1 -1
  99. package/lib/devextreme-license.d.ts +1 -0
  100. package/lib/devextreme-license.js +3 -0
  101. package/lib/helper/Globalization.d.ts +1 -1
  102. package/lib/helper/SDKUI_Globals.d.ts +110 -0
  103. package/lib/helper/SDKUI_Globals.js +151 -0
  104. package/lib/helper/SDKUI_Localizator.d.ts +55 -0
  105. package/lib/helper/SDKUI_Localizator.js +550 -0
  106. package/lib/helper/TMAppUpdatedModal.d.ts +2 -0
  107. package/lib/helper/TMAppUpdatedModal.js +134 -0
  108. package/lib/helper/TMIcons.d.ts +1 -0
  109. package/lib/helper/TMIcons.js +3 -0
  110. package/lib/helper/TMUtils.d.ts +51 -4
  111. package/lib/helper/TMUtils.js +272 -11
  112. package/lib/helper/dataGridSearchHelper.d.ts +28 -0
  113. package/lib/helper/dataGridSearchHelper.js +51 -0
  114. package/lib/helper/dcmtsHelper.d.ts +20 -0
  115. package/lib/helper/dcmtsHelper.js +58 -1
  116. package/lib/helper/helpers.d.ts +23 -1
  117. package/lib/helper/helpers.js +57 -1
  118. package/lib/helper/index.d.ts +2 -0
  119. package/lib/helper/index.js +2 -0
  120. package/lib/helper/queryHelper.d.ts +6 -1
  121. package/lib/helper/queryHelper.js +8 -3
  122. package/lib/hooks/tmDistinctValuesGridHelper.d.ts +16 -0
  123. package/lib/hooks/tmDistinctValuesGridHelper.js +31 -0
  124. package/lib/hooks/useArchiveListForm.d.ts +39 -0
  125. package/lib/hooks/useArchiveListForm.js +46 -0
  126. package/lib/hooks/useCaseFlowApprove.d.ts +56 -0
  127. package/lib/hooks/useCaseFlowApprove.js +157 -0
  128. package/lib/hooks/useDataUserIdItem.d.ts +1 -0
  129. package/lib/hooks/useDataUserIdItem.js +1 -0
  130. package/lib/hooks/useDocumentOperations.d.ts +4 -0
  131. package/lib/hooks/useDocumentOperations.js +52 -10
  132. package/lib/hooks/useMultiMasterDetailDcmts.d.ts +113 -0
  133. package/lib/hooks/useMultiMasterDetailDcmts.js +760 -0
  134. package/lib/hooks/useRelatedDocuments.d.ts +1 -0
  135. package/lib/hooks/useRelatedDocuments.js +22 -27
  136. package/lib/hooks/useShowDossiersV5.d.ts +12 -0
  137. package/lib/hooks/useShowDossiersV5.js +37 -0
  138. package/lib/hooks/useTMDistinctValuesMetadataDisplay.d.ts +18 -0
  139. package/lib/hooks/useTMDistinctValuesMetadataDisplay.js +103 -0
  140. package/lib/hooks/useTMDistinctValuesQuickSearch.d.ts +49 -0
  141. package/lib/hooks/useTMDistinctValuesQuickSearch.js +307 -0
  142. package/lib/hooks/useTMDistinctValuesSelection.d.ts +42 -0
  143. package/lib/hooks/useTMDistinctValuesSelection.js +103 -0
  144. package/lib/hooks/useTMDistinctValuesSource.d.ts +29 -0
  145. package/lib/hooks/useTMDistinctValuesSource.js +105 -0
  146. package/lib/index.d.ts +2 -0
  147. package/lib/index.js +5 -2
  148. package/lib/services/caseflow/CaseFlowService.d.ts +236 -0
  149. package/lib/services/caseflow/CaseFlowService.js +693 -0
  150. package/lib/services/caseflow/CaseFlowTemplateCacheService.d.ts +28 -0
  151. package/lib/services/caseflow/CaseFlowTemplateCacheService.js +121 -0
  152. package/lib/services/caseflow/caseFlowNameCache.d.ts +32 -0
  153. package/lib/services/caseflow/caseFlowNameCache.js +116 -0
  154. package/lib/services/caseflow/caseFlowWorkItemUtils.d.ts +61 -0
  155. package/lib/services/caseflow/caseFlowWorkItemUtils.js +113 -0
  156. package/lib/services/index.d.ts +4 -0
  157. package/lib/services/index.js +4 -0
  158. package/lib/services/platform_services.d.ts +1 -1
  159. package/package.json +9 -5
@@ -1,11 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import TMDcmtPreview from './TMDcmtPreview';
4
- import { AccessLevelsEx, AppModules, ArchiveConstraints, ArchiveEngineByID, DcmtTypeListCacheService, DossierCacheService, LayoutCacheService, LayoutModes, MetadataDataDomains, MetadataDataTypes, ObjectClasses, ResultTypes, SDK_Globals, SDK_Localizator, SystemMIDsAsNumber, SystemTIDs, Task_States, TID_DID, UpdateEngineByID, UserListCacheService, ValidationItem, WorkflowCacheService, WorkingGroupCacheService, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
4
+ import { AccessLevels, AccessLevelsEx, AppModules, ArchiveConstraints, ArchiveEngineByID, DcmtTypeDescriptor, DcmtTypeListCacheService, DcmtTypePermission, DossierCacheService, LayoutCacheService, LayoutModes, MetadataDataDomains, MetadataDataTypes, MetadataFormats, ObjectClasses, ResultTypes, SDK_Globals, SDK_Localizator, SystemMIDsAsNumber, SystemTIDs, Task_States, TID_DID, UpdateEngineByID, UserListCacheService, ValidationItem, WorkflowCacheService, WorkingGroupCacheService, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
5
5
  import { FormModes, SearchResultContext } from '../../../ts';
6
6
  import { DeviceType, useDeviceType } from '../../base/TMDeviceProvider';
7
7
  import { getWorkItemSetIDAsync, handleArchiveVisibility, searchResultToMetadataValues } from '../../../helper/queryHelper';
8
- import { genUniqueId, IconShow, SDKUI_Localizator, updateMruTids, IconBoard, IconDcmtTypeSys, calcIsModified, IconMenuVertical, Globalization, getListMaxItems, getSystemMetadata, IconBoxArchiveIn, IconClear, IconUndo, SDKUI_Globals, IconPreview, isTaskMoreInfo, IconWorkflow, IconSearch, deepCompare, IconActivity, getExceptionMessage, isApprovalWorkflowView, getDcmtCicoStatus, buildWorkItemsFromWFCtrl, IconLock, getDcmtFormToolbarVisibility, taskModalSizes } from '../../../helper';
8
+ import { genUniqueId, IconShow, SDKUI_Localizator, updateMruTids, IconBoard, IconDcmtTypeSys, calcIsModified, IconMenuVertical, Globalization, getListMaxItems, getSystemMetadata, IconBoxArchiveIn, IconClear, IconUndo, SDKUI_Globals, IconPreview, isTaskMoreInfo, IconWorkflow, IconSearch, deepCompare, IconActivity, getExceptionMessage, isApprovalWorkflowView, getDcmtCicoStatus, buildWorkItemsFromWFCtrl, IconLock, getDcmtFormToolbarVisibility, taskModalSizes, IconArchiveMultipleDetailDocuments, isNotGrantedDraftsDTD } from '../../../helper';
9
9
  import { hasDetailRelations, hasMasterRelations } from '../../../helper/dcmtsHelper';
10
10
  import { Gutters, TMColors } from '../../../utils/theme';
11
11
  import { StyledFormButtonsContainer, StyledLoadingContainer, StyledSpinner, StyledToolbarCardContainer } from '../../base/Styled';
@@ -26,6 +26,7 @@ import { useTMPanelManagerContext } from '../../layout/panelManager/TMPanelManag
26
26
  import TMPanelManagerContainer from '../../layout/panelManager/TMPanelManagerContainer';
27
27
  import { TMPanelManagerWithPersistenceProvider } from '../../layout/panelManager/TMPanelManagerWithPersistenceProvider';
28
28
  import { useWorkflowApprove } from '../../../hooks/useWorkflowApprove';
29
+ import { useCaseFlowApprove } from '../../../hooks/useCaseFlowApprove';
29
30
  import TMBlogCommentForm from '../blog/TMBlogCommentForm';
30
31
  import WFDiagram from '../workflow/diagram/WFDiagram';
31
32
  import TMTooltip from '../../base/TMTooltip';
@@ -39,6 +40,8 @@ import TMToppyDraggableHelpCenter from '../assistant/TMToppyDraggableHelpCenter'
39
40
  import TMTaskForm from '../tasks/TMTaskForm';
40
41
  import { useDocumentOperations } from '../../../hooks/useDocumentOperations';
41
42
  import TMDcmtFormActionButtons from './TMDcmtFormActionButtons';
43
+ import { useArchiveListForm } from '../../../hooks/useArchiveListForm';
44
+ import TMMultiMasterDetailDcmtsForm from './TMMultiMasterDetailDcmtsForm';
42
45
  //#region Interfaces, Types and Enums
43
46
  /**
44
47
  * Definisce il contesto da cui è stato invocato il TMDcmtForm.
@@ -57,7 +60,7 @@ export var InvocationContext;
57
60
  let abortControllerLocal = new AbortController();
58
61
  ;
59
62
  //#endregion
60
- const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMode = FormModes.Update, invocationContext = InvocationContext.Default, showHeader = true, showBackButton = true, showDcmtFormSidebar = true, isClosable = false, showTodoDcmtForm = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, isModal = false, titleModal, widthModal = "100%", heightModal = "100%", allowNavigation = true, canNext, canPrev, count, itemIndex, onNext, onPrev, inputFile = null, inputMids = [], connectorFileSave = undefined, isSharedDcmt = false, sharedSourceTID, sharedSourceDID, allowRelations = true, allowButtonsRefs = false, openS4TViewer = false, enableDragDropOverlay = false, editPdfForm = false, onClose, onSavedAsyncCallback, onSaveRecents, onWFOperationCompleted, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, onTaskCompleted, onTaskCreateRequest, moreInfoTasks, taskFormDialogComponent, handleNavigateToWGs, handleNavigateToDossiers, onReferenceClick, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor, s4TViewerDialogComponent, onScanRequest, passToSearch, fetchRemoteCertificates, datagridUtility, graphometricManager }) => {
63
+ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMode = FormModes.Update, invocationContext = InvocationContext.Default, showHeader = true, showBackButton = true, showDcmtFormSidebar = true, isClosable = false, showTodoDcmtForm = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, isModal = false, titleModal, widthModal = "100%", heightModal = "100%", allowNavigation = true, canNext, canPrev, count, itemIndex, onNext, onPrev, inputFile = null, inputMids = [], connectorFileSave = undefined, isSharedDcmt = false, sharedSourceTID, sharedSourceDID, allowRelations = true, allowButtonsRefs = false, openS4TViewer = false, enableDragDropOverlay = false, editPdfForm = false, onClose, onSavedAsyncCallback, onSaveRecents, onWFOperationCompleted, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, onTaskCompleted, onTaskCreateRequest, moreInfoTasks, taskFormDialogComponent, handleNavigateToWGs, handleNavigateToDossiers, onReferenceClick, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor, s4TViewerDialogComponent, onScanRequest, passToSearch, archiveListMode, fetchRemoteCertificates, datagridUtility, graphometricManager }) => {
61
64
  const { onRefreshSearchAsyncDatagrid, onRefreshBlogDatagrid, onRefreshPreviewDatagrid } = datagridUtility || {};
62
65
  const floatingBarContainerRef = useRef(null);
63
66
  const [id, setID] = useState('');
@@ -96,6 +99,10 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
96
99
  const [isOpenFormulaEditor, setIsOpenFormulaEditor] = useState(false);
97
100
  const [currentTIDHasDetailRelations, setCurrentTIDHasDetailRelations] = useState();
98
101
  const [currentTIDHasMasterRelations, setCurrentTIDHasMasterRelations] = useState();
102
+ // Modale "Archivia documenti di dettaglio multipli" aperto dall'azione secondaria del form di archiviazione:
103
+ // dopo aver archiviato il master si apre il modale con il master appena archiviato come documento di partenza.
104
+ const [showMultiDetailArchiveModal, setShowMultiDetailArchiveModal] = useState(false);
105
+ const [multiDetailMasterDcmts, setMultiDetailMasterDcmts] = useState([]);
99
106
  const [currentDcmt, setCurrentDcmt] = useState();
100
107
  const [dcmtFile, setDcmtFile] = useState(null);
101
108
  const [focusedMetadataValue, setFocusedMetadataValue] = useState();
@@ -116,6 +123,10 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
116
123
  const [wfError, setWfError] = useState(null);
117
124
  const [metadataDcmtOrigin, setMetadataDcmtOrigin] = useState(null);
118
125
  const { workflowApproveData, getWorkItemsByDID } = useWorkflowApprove();
126
+ // Attività delle PRATICHE (CaseFlow) su questo documento. Come per il workflow
127
+ // la scoperta avviene QUI: da qualunque punto si apra il form, l'utente trova
128
+ // le sue azioni nel Toppy.
129
+ const { caseFlowWorkItems, completeCaseFlowWorkItem, rejectCaseFlowWorkItem } = useCaseFlowApprove(TID, DID);
119
130
  // Get the current device type (e.g., mobile, tablet, desktop) using a custom hook.
120
131
  const deviceType = useDeviceType();
121
132
  // This avoids unnecessary re-renders by only recalculating when deviceType changes.
@@ -325,6 +336,14 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
325
336
  }
326
337
  // Carica DTD e metadata
327
338
  let dtd = await DcmtTypeListCacheService.GetWithNotGrantedAsync(TID, DID, getMetadataResult);
339
+ // Le bozze dei gruppi di lavoro vivono su un tipo documento non autorizzato e quindi privo di
340
+ // permessi: si concede la sola lettura del file, altrimenti non sarebbe scaricabile dal form.
341
+ if (isNotGrantedDraftsDTD(dtd)) {
342
+ const perm = new DcmtTypePermission();
343
+ perm.canRetrieveFile = AccessLevels.Yes;
344
+ // Su una copia: GetWithNotGrantedAsync restituisce l'istanza in cache, condivisa con gli altri consumer
345
+ dtd = Object.assign(new DcmtTypeDescriptor(), dtd, { perm });
346
+ }
328
347
  setFromDTD(dtd);
329
348
  if (layoutMode === LayoutModes.Update || (layoutMode === LayoutModes.Ark && DID)) {
330
349
  await setMetadataList(dtd?.metadata ?? [], getMetadataResult);
@@ -450,7 +469,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
450
469
  openTaskFormHandler,
451
470
  },
452
471
  });
453
- const { handleSignApprove, checkoutInfo: { showCicoWaitPanel, cicoWaitPanelTitle, showCicoPrimaryProgress, cicoPrimaryProgressText, cicoPrimaryProgressValue, cicoPrimaryProgressMax, }, dcmtOperations: { abortController, showWaitPanel, showPrimary, waitPanelTitle, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, }, relatedDocumentsInfo: { isOpenDetails, isOpenMaster, checkRelatedDcmtsArchiveCapability, checkManyToManyCapability, }, toppyOperations: { updateShowApprovePopup, updateShowRejectPopup, updateShowReAssignPopup, updateShowMoreInfoPopup } } = features;
472
+ const { handleSignApprove, checkoutInfo: { showCicoWaitPanel, cicoWaitPanelTitle, showCicoPrimaryProgress, cicoPrimaryProgressText, cicoPrimaryProgressValue, cicoPrimaryProgressMax, }, dcmtOperations: { abortController, showWaitPanel, showPrimary, waitPanelTitle, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, }, relatedDocumentsInfo: { isOpenDetails, isOpenMaster, canArchiveDetailRelation, checkRelatedDcmtsArchiveCapability, checkManyToManyCapability, }, toppyOperations: { updateShowApprovePopup, updateShowRejectPopup, updateShowReAssignPopup, updateShowMoreInfoPopup } } = features;
454
473
  useEffect(() => {
455
474
  const fetchAllUsers = async () => {
456
475
  const users = await UserListCacheService.GetAllAsync();
@@ -804,11 +823,91 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
804
823
  // Verifica che ci siano riferimenti renderizzabili (solo Dossier o WorkingGroup)
805
824
  return dcmtReferences.some(ref => ref.objClass === ObjectClasses.Dossier || ref.objClass === ObjectClasses.WorkingGroup);
806
825
  }, [allowButtonsRefs, layoutMode, dcmtReferences, isOpenDetails, isOpenMaster]);
807
- const isToppyVisible = useMemo(() => Boolean((showToppyForApprove || showToppyForCompleteMoreInfo || showToppyForReferences) && !openS4TViewer && !showTodoDcmtForm && !editPdfForm), [showToppyForApprove, showToppyForCompleteMoreInfo, showToppyForReferences, openS4TViewer, showTodoDcmtForm, editPdfForm]);
808
- const isModified = useMemo(() => calcIsModified(formData, formDataOrig), [formData, formDataOrig]);
826
+ // Attività di pratica: stesse condizioni dell'approvazione workflow (documento
827
+ // in consultazione, senza errori, non dentro master/detail).
828
+ const showToppyForCaseFlow = useMemo(() => layoutMode === LayoutModes.Update && !fetchError && caseFlowWorkItems.length > 0 && !isOpenDetails && !isOpenMaster, [layoutMode, fetchError, caseFlowWorkItems.length, isOpenDetails, isOpenMaster]);
829
+ const isToppyVisible = useMemo(() => Boolean((showToppyForApprove || showToppyForCompleteMoreInfo || showToppyForReferences || showToppyForCaseFlow) && !openS4TViewer && !showTodoDcmtForm && !editPdfForm), [showToppyForApprove, showToppyForCompleteMoreInfo, showToppyForReferences, showToppyForCaseFlow, openS4TViewer, showTodoDcmtForm, editPdfForm]);
830
+ const handleClearForm = useCallback(() => {
831
+ let data = structuredClone(formData);
832
+ if (!data || data.length === 0)
833
+ return;
834
+ for (let md of data) {
835
+ if (!md.mid)
836
+ continue;
837
+ if (md.mid > 99) {
838
+ const defaultValue = md.md?.defaultValue;
839
+ if (defaultValue) {
840
+ if (FormulaHelper.isFormula(defaultValue)) {
841
+ md.value = undefined;
842
+ }
843
+ else {
844
+ md.value = defaultValue;
845
+ }
846
+ }
847
+ else if (formDataOrig.find(metadata => metadata.mid === md.mid)?.value === undefined) {
848
+ if (md.value)
849
+ md.value = undefined;
850
+ }
851
+ else if (md.value && md.value.length > 0) {
852
+ md.value = '';
853
+ }
854
+ }
855
+ }
856
+ setFormData(data);
857
+ }, [formData, formDataOrig]);
858
+ // Modalità "aggiungi a elenco" (archiviazione dettagli multipli): tutta la logica specifica è nell'hook.
859
+ const archiveList = useArchiveListForm({
860
+ mode: archiveListMode,
861
+ editingRowValues: inputMids,
862
+ formDataOrig,
863
+ formDataRef,
864
+ dcmtFileRef,
865
+ tid: TID,
866
+ isModal,
867
+ id,
868
+ clearForm: handleClearForm,
869
+ });
870
+ const isModified = useMemo(() => calcIsModified(formData, archiveList.referenceValues), [formData, archiveList.referenceValues]);
809
871
  const formToolbar = useMemo(() => _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [allowNavigation && canPrev != undefined && _jsx("p", { style: { textAlign: 'center', padding: '1px 4px', display: 'flex' }, children: `${itemIndex}/${count}` }), allowNavigation && canPrev != undefined && _jsx(TMSaveFormButtonPrevious, { btnStyle: 'icon', iconColor: 'white', isModified: isModified, formMode: formMode, canPrev: canPrev, onPrev: onPrev }), allowNavigation && canNext != undefined && _jsx(TMSaveFormButtonNext, { btnStyle: 'icon', iconColor: 'white', isModified: isModified, formMode: formMode, canNext: canNext, onNext: onNext }), layoutMode === LayoutModes.Update &&
810
- _jsx(ContextMenu, { items: operationItems, trigger: "left", children: _jsx(IconMenuVertical, { color: 'white', cursor: 'pointer' }) }), layoutMode === LayoutModes.Ark &&
811
- _jsx(TMTooltip, { content: SDKUI_Localizator.PassToSearch, position: 'bottom', children: _jsx(IconSearch, { style: { cursor: 'pointer' }, onClick: handlePassToSearch }) })] }), [allowNavigation, canPrev, canNext, itemIndex, count, isModified, formMode, onPrev, onNext, layoutMode, operationItems, handlePassToSearch]);
872
+ _jsx(ContextMenu, { items: operationItems, trigger: "left", children: _jsx(IconMenuVertical, { color: 'white', cursor: 'pointer' }) }), layoutMode === LayoutModes.Ark && !archiveList.enabled &&
873
+ _jsx(TMTooltip, { content: SDKUI_Localizator.PassToSearch, position: 'bottom', children: _jsx(IconSearch, { style: { cursor: 'pointer' }, onClick: handlePassToSearch }) })] }), [allowNavigation, canPrev, canNext, itemIndex, count, isModified, formMode, onPrev, onNext, layoutMode, operationItems, handlePassToSearch, archiveList.enabled]);
874
+ // Ricarica del pannello metadati: invalida le cache del tipo documento e del layout, così la
875
+ // definizione dei metadati e la disposizione del form vengono rilette dal server, poi ricostruisce il form
876
+ const reloadFormMetadataAsync = useCallback(async () => {
877
+ if (!TID)
878
+ return;
879
+ // refreshCache invalida la voce in cache e rilegge il tipo documento con i metadati:
880
+ // la GetWithNotGrantedAsync della load successiva trova quella appena aggiornata
881
+ await DcmtTypeListCacheService.GetAsync(TID, true, undefined, false, true);
882
+ LayoutCacheService.Remove(TID, layoutMode);
883
+ if (layoutMode === LayoutModes.Update)
884
+ LayoutCacheService.Remove(TID, LayoutModes.None);
885
+ await loadDocumentFormDataAsync();
886
+ }, [TID, layoutMode, loadDocumentFormDataAsync]);
887
+ // Il ricaricamento ricostruisce il form: con valori inseriti e non salvati chiede prima conferma.
888
+ // In archiviazione la ricostruzione sgancia anche il file, quindi va confermata pure in quel caso.
889
+ const handleRefreshFormMetadataAsync = useCallback(async () => {
890
+ const hasPendingChanges = isModified || (layoutMode === LayoutModes.Ark && !!dcmtFile);
891
+ if (!hasPendingChanges) {
892
+ await reloadFormMetadataAsync();
893
+ return;
894
+ }
895
+ const isConfirmed = await new Promise(resolve => {
896
+ let isAnswered = false;
897
+ TMMessageBoxManager.show({
898
+ parentId: isModal ? "TMDcmtFormShowConfirmForClose-" + id : undefined,
899
+ title: SDKUI_Localizator.Refresh,
900
+ message: SDKUI_Localizator.ConfirmOnCancel,
901
+ buttons: [ButtonNames.YES, ButtonNames.NO],
902
+ onButtonClick: (e) => { isAnswered = true; resolve(e === ButtonNames.YES); },
903
+ // Chiusura dalla X: senza questa la Promise non si risolverebbe e il loader resterebbe acceso
904
+ onClose: () => { if (!isAnswered)
905
+ resolve(false); }
906
+ });
907
+ });
908
+ if (isConfirmed)
909
+ await reloadFormMetadataAsync();
910
+ }, [isModified, layoutMode, dcmtFile, isModal, id, reloadFormMetadataAsync]);
812
911
  const handleUndo = useCallback(() => {
813
912
  setFormData(structuredClone(formDataOrig));
814
913
  }, [formDataOrig]);
@@ -964,55 +1063,63 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
964
1063
  const isDuplication = layoutMode === LayoutModes.Ark && DID;
965
1064
  if (isDuplication)
966
1065
  onClose?.();
1066
+ // Ritorna il DID del documento appena archiviato, così il chiamante può proseguire
1067
+ // (es. aprire il modale di archiviazione dei documenti di dettaglio sul master appena creato).
1068
+ return newDID;
967
1069
  }
968
1070
  catch (err) {
969
1071
  TMExceptionBoxManager.show({ exception: err });
1072
+ return undefined;
970
1073
  }
971
1074
  finally {
972
1075
  setShowWaitPanelLocal(false);
973
1076
  setUseWaitPanelLocalState(false);
974
1077
  }
975
1078
  }, [TID, connectorFileSave, onSavedAsyncCallback, onSaveRecents, onClose, DID, setMetadataList, handleReset, layoutMode, isSharedDcmt]);
1079
+ // Messaggio di conferma dell'archiviazione in base al vincolo del tipo documento (ArchiveConstraints).
1080
+ const getArchiveConfirmMessage = useCallback(() => {
1081
+ // Con connectorFileSave il file viene prodotto dal connettore solo alla conferma: si assume che ci sarà.
1082
+ const hasFile = !!connectorFileSave || !!dcmtFileRef.current;
1083
+ switch (fromDTDRef.current?.archiveConstraint) {
1084
+ // Solo metadati: il file non è previsto.
1085
+ case ArchiveConstraints.OnlyMetadata: return SDKUI_Localizator.ArchiveDocument_Confirm;
1086
+ // File obbligatorio: senza file il pulsante Archivia è disabilitato, quindi qui il file c'è.
1087
+ case ArchiveConstraints.ContentCompulsory: return SDKUI_Localizator.ArchiveDocument_Confirm;
1088
+ // Metadati e/o file: se il file manca lo segnala, come in v5.
1089
+ default: return hasFile ? SDKUI_Localizator.ArchiveDocument_Confirm : SDKUI_Localizator.ArchiveOnlyMetadata_Confirm;
1090
+ }
1091
+ }, [connectorFileSave]);
976
1092
  const handleConfirmAction = useCallback(async () => {
1093
+ const isUpdate = layoutMode === LayoutModes.Update;
977
1094
  TMMessageBoxManager.show({
978
1095
  parentId: isModal ? "TMDcmtFormShowConfirmForClose-" + id : undefined,
979
1096
  buttons: [ButtonNames.YES, ButtonNames.NO],
980
- message: layoutMode === LayoutModes.Update ? SDKUI_Localizator.SaveQuestion : 'Sei sicuro di voler archiviare questo documento?',
981
- onButtonClick(e) {
1097
+ message: isUpdate ? SDKUI_Localizator.SaveQuestion : getArchiveConfirmMessage(),
1098
+ onButtonClick: (e) => {
982
1099
  if (e !== ButtonNames.YES)
983
1100
  return;
984
- layoutMode === LayoutModes.Update ? handleSave() : handleArchiveCompleted();
1101
+ isUpdate ? handleSave() : handleArchiveCompleted();
985
1102
  },
986
1103
  });
987
- }, [isModal, id, layoutMode, handleSave, handleArchiveCompleted]);
988
- const handleClearForm = useCallback(() => {
989
- let data = structuredClone(formData);
990
- if (!data || data.length === 0)
991
- return;
992
- for (let md of data) {
993
- if (!md.mid)
994
- continue;
995
- if (md.mid > 99) {
996
- const defaultValue = md.md?.defaultValue;
997
- if (defaultValue) {
998
- if (FormulaHelper.isFormula(defaultValue)) {
999
- md.value = undefined;
1000
- }
1001
- else {
1002
- md.value = defaultValue;
1003
- }
1004
- }
1005
- else if (formDataOrig.find(metadata => metadata.mid === md.mid)?.value === undefined) {
1006
- if (md.value)
1007
- md.value = undefined;
1008
- }
1009
- else if (md.value && md.value.length > 0) {
1010
- md.value = '';
1011
- }
1012
- }
1013
- }
1014
- setFormData(data);
1015
- }, [formData, formDataOrig]);
1104
+ }, [isModal, id, layoutMode, getArchiveConfirmMessage, handleSave, handleArchiveCompleted]);
1105
+ // Azione secondaria del form di archiviazione: archivia il master e, subito dopo,
1106
+ // apre il modale di archiviazione dei documenti di dettaglio multipli usando il master appena creato.
1107
+ const handleArchiveMasterAndDetails = useCallback(async () => {
1108
+ TMMessageBoxManager.show({
1109
+ parentId: isModal ? "TMDcmtFormShowConfirmForClose-" + id : undefined,
1110
+ buttons: [ButtonNames.YES, ButtonNames.NO],
1111
+ message: SDKUI_Localizator.ArchiveMasterAndDetails_Confirm,
1112
+ onButtonClick: async (e) => {
1113
+ if (e !== ButtonNames.YES)
1114
+ return;
1115
+ const newDID = await handleArchiveCompleted();
1116
+ if (newDID === undefined || newDID === null)
1117
+ return;
1118
+ setMultiDetailMasterDcmts([{ TID: TID, DID: newDID }]);
1119
+ setShowMultiDetailArchiveModal(true);
1120
+ },
1121
+ });
1122
+ }, [isModal, id, handleArchiveCompleted, TID]);
1016
1123
  const clearFormBtnDisabled = useMemo(() => formData.filter(md => md.mid && md.value && md.mid > 99 && md.value.length > 0).length > 0, [formData]);
1017
1124
  const archiveBtnDisabled = useMemo(() => layoutMode === LayoutModes.Update || (fromDTD?.archiveConstraint === ArchiveConstraints.ContentCompulsory && !dcmtFile) || validationItems.length > 0, [layoutMode, fromDTD?.archiveConstraint, dcmtFile, validationItems.length]);
1018
1125
  const undoBtnDisabled = useMemo(() => layoutMode === LayoutModes.Update || !isModified, [layoutMode, isModified]);
@@ -1021,10 +1128,14 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1021
1128
  const metadataValuesSource = useMemo(() => {
1022
1129
  return applyMetadataFilter(formData, showAll, listMaxItems, TID);
1023
1130
  }, [showAll, formData, listMaxItems, TID]);
1024
- const metadataValuesSourceOrig = useMemo(() => {
1025
- return applyMetadataFilter(formDataOrig, showAll, listMaxItems, TID);
1026
- }, [showAll, formDataOrig, listMaxItems, TID]);
1131
+ const metadataValuesSourceOrig = useMemo(() =>
1132
+ // I valori di riferimento (in modifica riga includono i valori già caricati) li calcola l'hook:
1133
+ // così i campi pre-compilati non si colorano di giallo finché l'utente non li cambia davvero.
1134
+ applyMetadataFilter(archiveList.referenceValues, showAll, listMaxItems, TID), [showAll, archiveList.referenceValues, listMaxItems, TID]);
1027
1135
  const handleClose = useCallback(() => {
1136
+ // Modalità "aggiungi a elenco": la X non archivia ma aggiorna l'elenco (gestita dall'hook).
1137
+ if (archiveList.requestClose(isModified, onClose))
1138
+ return;
1028
1139
  if (!isModified) {
1029
1140
  onClose?.();
1030
1141
  return;
@@ -1045,7 +1156,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1045
1156
  }
1046
1157
  }
1047
1158
  });
1048
- }, [isModified, onClose, isModal, id, handleSave]);
1159
+ }, [isModified, onClose, isModal, id, handleSave, archiveList]);
1049
1160
  const getFormula = useCallback(() => {
1050
1161
  let fd = new FormulaDescriptor();
1051
1162
  fd.expression = FormulaHelper.isFormula(focusedMetadataValue?.value) ? FormulaHelper.removeFormulaTag(focusedMetadataValue?.value) : undefined;
@@ -1118,7 +1229,14 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1118
1229
  break;
1119
1230
  }
1120
1231
  } }), _jsxs(StyledFormButtonsContainer, { children: [_jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: 10 }, children: _jsx("div", { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', gap: '8px' }, children: layoutMode === LayoutModes.Update ? _jsxs(_Fragment, { children: [_jsx(TMSaveFormButtonSave, { showTooltip: false, btnStyle: 'advanced', advancedColor: '#f09c0a', isModified: isModified, formMode: formMode, errorsCount: validationItems.filter(o => o.ResultType == ResultTypes.ERROR).length, onSaveAsync: handleConfirmAction }), _jsx(TMSaveFormButtonUndo, { btnStyle: 'toolbar', showTooltip: true, color: 'primary', isModified: isModified, formMode: formMode, onUndo: handleUndo })] }) :
1121
- _jsxs(_Fragment, { children: [_jsx(TMButton, { disabled: archiveBtnDisabled, btnStyle: 'advanced', icon: _jsx(IconBoxArchiveIn, {}), width: 'auto', showTooltip: false, caption: SDKUI_Localizator.Archive, advancedColor: TMColors.success, onClick: handleConfirmAction }), _jsx(TMButton, { disabled: !clearFormBtnDisabled, btnStyle: 'advanced', icon: _jsx(IconClear, {}), width: 'auto', showTooltip: false, caption: SDKUI_Localizator.Clear, advancedColor: TMColors.tertiary, onClick: handleClearForm }), DID && _jsx(TMButton, { disabled: undoBtnDisabled, btnStyle: 'advanced', icon: _jsx(IconUndo, {}), width: '150px', showTooltip: false, caption: SDKUI_Localizator.Undo, advancedColor: TMColors.tertiary, onClick: handleUndo })] }) }) }), customButton && _jsx(TMCustomButton, { button: customButton, formData: formData, selectedItems: [], onClose: () => setCustomButton(undefined) }), totalItems > listMaxItems &&
1232
+ archiveList.enabled ?
1233
+ _jsxs(_Fragment, { children: [_jsx(TMButton, { disabled: archiveBtnDisabled, btnStyle: 'advanced', icon: _jsx(IconBoxArchiveIn, {}), width: 'auto', showTooltip: false, caption: archiveList.isEditingRow ? SDKUI_Localizator.Update : SDKUI_Localizator.Add, advancedColor: TMColors.success, onClick: archiveList.submit }), _jsx(TMButton, { disabled: !clearFormBtnDisabled, btnStyle: 'advanced', icon: _jsx(IconClear, {}), width: 'auto', showTooltip: false, caption: SDKUI_Localizator.Clear, advancedColor: TMColors.tertiary, onClick: handleClearForm })] }) :
1234
+ _jsxs(_Fragment, { children: [_jsx(TMButton, { disabled: archiveBtnDisabled, btnStyle: 'advanced', icon: _jsx(IconBoxArchiveIn, {}), width: canArchiveDetailRelation ? '120px' : 'auto', showTooltip: false, caption: SDKUI_Localizator.Archive, advancedColor: TMColors.success, onClick: handleConfirmAction, secondaryActions: canArchiveDetailRelation ? [{
1235
+ name: SDKUI_Localizator.ArchiveMasterAndMultipleDetailDocuments,
1236
+ icon: _jsx(IconArchiveMultipleDetailDocuments, {}),
1237
+ disabled: archiveBtnDisabled,
1238
+ onClick: handleArchiveMasterAndDetails,
1239
+ }] : undefined }), _jsx(TMButton, { disabled: !clearFormBtnDisabled, btnStyle: 'advanced', icon: _jsx(IconClear, {}), width: 'auto', showTooltip: false, caption: SDKUI_Localizator.Clear, advancedColor: TMColors.tertiary, onClick: handleClearForm }), DID && _jsx(TMButton, { disabled: undoBtnDisabled, btnStyle: 'advanced', icon: _jsx(IconUndo, {}), width: '150px', showTooltip: false, caption: SDKUI_Localizator.Undo, advancedColor: TMColors.tertiary, onClick: handleUndo })] }) }) }), customButton && _jsx(TMCustomButton, { button: customButton, formData: formData, selectedItems: [], onClose: () => setCustomButton(undefined) }), totalItems > listMaxItems &&
1122
1240
  !isApprView &&
1123
1241
  TID !== SystemTIDs.Drafts &&
1124
1242
  !shouldShowAll &&
@@ -1149,6 +1267,8 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1149
1267
  handleConfirmAction,
1150
1268
  handleUndo,
1151
1269
  handleClearForm,
1270
+ canArchiveDetailRelation,
1271
+ handleArchiveMasterAndDetails,
1152
1272
  isReadOnlyOriginCallback,
1153
1273
  metadataDcmtOrigin?.fromTID,
1154
1274
  ]);
@@ -1286,6 +1406,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1286
1406
  allowMaximize: !isMobile,
1287
1407
  onBack: getOnBackHandler(true),
1288
1408
  onClose: isClosable ? () => { } : undefined,
1409
+ onRefresh: handleRefreshFormMetadataAsync,
1289
1410
  toolbar: allowNavigation ? formToolbar : _jsx(_Fragment, {})
1290
1411
  },
1291
1412
  },
@@ -1375,7 +1496,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1375
1496
  },
1376
1497
  ];
1377
1498
  return panels;
1378
- }, [fromDTD, showBackButton, tmDcmtForm, tmBlog, tmSysMetadata, tmDcmtPreview, tmWF, tmDcmtTasks, isPreviewDisabled, isSysMetadataDisabled, isBoardDisabled, isWFDisabled, inputFile, isClosable, allTasks, DID, TID, isReadOnlyOriginCallback, metadataDcmtOrigin?.fromTID]);
1499
+ }, [fromDTD, showBackButton, tmDcmtForm, tmBlog, tmSysMetadata, tmDcmtPreview, tmWF, tmDcmtTasks, isPreviewDisabled, isSysMetadataDisabled, isBoardDisabled, isWFDisabled, inputFile, isClosable, allTasks, DID, TID, isReadOnlyOriginCallback, metadataDcmtOrigin?.fromTID, handleRefreshFormMetadataAsync]);
1379
1500
  // Retrieves the current document form setting based on the normalized TID
1380
1501
  const getCurrentDcmtFormSetting = () => {
1381
1502
  const settings = SDKUI_Globals.userSettings.dcmtFormSettings;
@@ -1443,7 +1564,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1443
1564
  for (const key of Object.keys(persistedState)) {
1444
1565
  if (key === 'tmWF') {
1445
1566
  // Hide tmWF
1446
- newState[key] = { ...persistedState[key], visible: false };
1567
+ newState[key] = { ...persistedState[key], visible: false, width: '0%' };
1447
1568
  }
1448
1569
  else if (otherVisiblePanels.includes(key)) {
1449
1570
  // Add extra width to visible panels
@@ -1470,6 +1591,8 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1470
1591
  const persistedState = invocationContext === InvocationContext.Todo ? settings?.layoutToDo : settings?.layout;
1471
1592
  return persistedState?.['tmWF']?.visible ?? false;
1472
1593
  };
1594
+ // Persisted tmWF visibility, read once at mount
1595
+ const persistedWFVisibleRef = useRef(getPersistedWFVisible());
1473
1596
  const onBlogCommentFormCustomSave = useCallback(async (blogPost) => {
1474
1597
  try {
1475
1598
  if (!moreInfoTasks || moreInfoTasks.length === 0) {
@@ -1557,7 +1680,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1557
1680
  overflow: 'hidden'
1558
1681
  }, children: [_jsxs("div", { style: { width: '100%', height: '100%', display: isOpenDetails || isOpenMaster ? 'none' : 'flex' }, children: [isNavigating && _jsx(Spinner, { description: SDKUI_Localizator.Loading, flat: false }), (fromDTD) && _jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: useWaitPanelLocalState ? showWaitPanelLocal : showWaitPanel, showWaitPanelPrimary: useWaitPanelLocalState ? showPrimaryLocal : showPrimary, showWaitPanelSecondary: useWaitPanelLocalState ? showSecondaryLocal : showSecondary, waitPanelTitle: useWaitPanelLocalState ? waitPanelTitleLocal : waitPanelTitle, waitPanelTextPrimary: useWaitPanelLocalState ? waitPanelTextPrimaryLocal : waitPanelTextPrimary, waitPanelValuePrimary: useWaitPanelLocalState ? waitPanelValuePrimaryLocal : waitPanelValuePrimary, waitPanelMaxValuePrimary: useWaitPanelLocalState ? waitPanelMaxValuePrimaryLocal : waitPanelMaxValuePrimary, waitPanelTextSecondary: useWaitPanelLocalState ? waitPanelTextSecondaryLocal : waitPanelTextSecondary, waitPanelValueSecondary: useWaitPanelLocalState ? waitPanelValueSecondaryLocal : waitPanelValueSecondary, waitPanelMaxValueSecondary: useWaitPanelLocalState ? waitPanelMaxValueSecondaryLocal : waitPanelMaxValueSecondary, isCancelable: useWaitPanelLocalState ? dcmtFile ? dcmtFile.size >= 1000000 : false : true, abortController: useWaitPanelLocalState ? abortControllerLocal : abortController, children: _jsxs(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showCicoWaitPanel, showWaitPanelPrimary: showCicoPrimaryProgress, waitPanelTitle: cicoWaitPanelTitle, waitPanelTextPrimary: cicoPrimaryProgressText, waitPanelValuePrimary: cicoPrimaryProgressValue, waitPanelMaxValuePrimary: cicoPrimaryProgressMax, isCancelable: true, abortController: abortControllerLocal, children: [(groupId && groupId.length > 0)
1559
1682
  ? _jsxs(_Fragment, { children: [_jsx(PanelDisabledStateHandler, { isWFDisabled: isWFDisabled, isSysMetadataDisabled: isSysMetadataDisabled, isBoardDisabled: isBoardDisabled, isDcmtTasksDisabled: isDcmtTasksDisabled, isPreviewDisabled: isPreviewDisabled }), _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", parentId: groupId, showToolbar: showDcmtFormSidebar })] })
1560
- : _jsxs(TMPanelManagerWithPersistenceProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: defaultPanelDimensions, initialDimensions: defaultPanelDimensions, initialMobilePanelId: 'tmDcmtForm', isPersistenceEnabled: !isMobile && layoutMode !== LayoutModes.Ark ? hasSavedLayout() : false, persistPanelStates: !isMobile && layoutMode !== LayoutModes.Ark ? (state) => persistPanelStates(state) : undefined, persistedPanelStates: layoutMode !== LayoutModes.Ark ? getPersistedPanelStates() : undefined, children: [_jsx(PanelDisabledStateHandler, { isWFDisabled: isWFDisabled, isSysMetadataDisabled: isSysMetadataDisabled, isBoardDisabled: isBoardDisabled, isDcmtTasksDisabled: isDcmtTasksDisabled, isPreviewDisabled: isPreviewDisabled, persistedWFVisible: getPersistedWFVisible() }), _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", parentId: groupId, showToolbar: showDcmtFormSidebar })] }), isOpenDistinctValues &&
1683
+ : _jsxs(TMPanelManagerWithPersistenceProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: defaultPanelDimensions, initialDimensions: defaultPanelDimensions, initialMobilePanelId: 'tmDcmtForm', isPersistenceEnabled: !isMobile && layoutMode !== LayoutModes.Ark ? hasSavedLayout() : false, persistPanelStates: !isMobile && layoutMode !== LayoutModes.Ark ? (state) => persistPanelStates(state) : undefined, persistedPanelStates: layoutMode !== LayoutModes.Ark ? getPersistedPanelStates() : undefined, children: [_jsx(PanelDisabledStateHandler, { isWFDisabled: isWFDisabled, isSysMetadataDisabled: isSysMetadataDisabled, isBoardDisabled: isBoardDisabled, isDcmtTasksDisabled: isDcmtTasksDisabled, isPreviewDisabled: isPreviewDisabled, persistedWFVisible: persistedWFVisibleRef.current }), _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", parentId: groupId, showToolbar: showDcmtFormSidebar })] }), isOpenDistinctValues &&
1561
1684
  _jsx(TMDistinctValues, { tid: TID, mid: focusedMetadataValue?.mid, isModal: true, showHeader: false, layoutMode: layoutMode, onClosePanelCallback: () => setIsOpenDistinctValues(false), onSelectionChanged: (e) => {
1562
1685
  if (!e)
1563
1686
  return;
@@ -1571,12 +1694,13 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1571
1694
  isEditable: true,
1572
1695
  value: FormulaHelper.addFormulaTag(newFormula.expression)
1573
1696
  }));
1574
- } }), (isModal && onClose) && _jsx("div", { id: "TMDcmtFormShowConfirmForClose-" + id })] }) }), _jsx(TMToppyDraggableHelpCenter, { isVisible: isToppyVisible, content: _jsx(TMDcmtFormActionButtons, { showToppyForApprove: showToppyForApprove, workItems: workItems, deviceType: deviceType, isMobile: isMobile, handleSignApprove: handleSignApprove, updateShowApprovePopup: updateShowApprovePopup, updateShowRejectPopup: updateShowRejectPopup, updateShowReAssignPopup: updateShowReAssignPopup, updateShowMoreInfoPopup: updateShowMoreInfoPopup, fromDTD: fromDTD, showToppyForCompleteMoreInfo: showToppyForCompleteMoreInfo, moreInfoTasks: moreInfoTasks, setShowCommentForm: setShowCommentForm, showToppyForReferences: showToppyForReferences, dcmtReferences: dcmtReferences, referenceActionMap: referenceActionMap, handleNavigateToReference: handleNavigateToReference, setShowMoreInfoTaskPopup: setShowMoreInfoTaskPopup, setShowMoreInfoTaskTask: setShowMoreInfoTaskTask }) })] }), (showCommentForm && TID && DID) &&
1697
+ } }), (isModal && onClose) && _jsx("div", { id: "TMDcmtFormShowConfirmForClose-" + id })] }) }), _jsx(TMToppyDraggableHelpCenter, { isVisible: isToppyVisible, content: _jsx(TMDcmtFormActionButtons, { showToppyForApprove: showToppyForApprove, workItems: workItems, caseFlowWorkItems: showToppyForCaseFlow ? caseFlowWorkItems : [], onCompleteCaseFlowWorkItem: completeCaseFlowWorkItem, onRejectCaseFlowWorkItem: rejectCaseFlowWorkItem, deviceType: deviceType, isMobile: isMobile, handleSignApprove: handleSignApprove, updateShowApprovePopup: updateShowApprovePopup, updateShowRejectPopup: updateShowRejectPopup, updateShowReAssignPopup: updateShowReAssignPopup, updateShowMoreInfoPopup: updateShowMoreInfoPopup, fromDTD: fromDTD, showToppyForCompleteMoreInfo: showToppyForCompleteMoreInfo, moreInfoTasks: moreInfoTasks, setShowCommentForm: setShowCommentForm, showToppyForReferences: showToppyForReferences, dcmtReferences: dcmtReferences, referenceActionMap: referenceActionMap, handleNavigateToReference: handleNavigateToReference, setShowMoreInfoTaskPopup: setShowMoreInfoTaskPopup, setShowMoreInfoTaskTask: setShowMoreInfoTaskTask }) })] }), (showCommentForm && TID && DID) &&
1575
1698
  _jsx(TMBlogCommentForm, { maxLength: 500, context: blogCommentFormContext, onClose: handleBlogCommentFormClose, onCustomSave: onBlogCommentFormCustomSave, participants: emptyParticipants, showAttachmentsSection: false, allArchivedDocumentsFileItems: emptyArchivedDocumentsFileItems })] }), renderDcmtOperations, renderFloatingBar] }));
1576
1699
  };
1577
1700
  return (_jsxs("div", { style: { width: '100%', height: '100%' }, children: [(isModal && onClose)
1578
1701
  ? _jsx(TMModal, { title: titleModal, onClose: handleClose, width: widthModal ?? '100%', height: heightModal ?? '100%', hidePopup: false, askClosingConfirm: true, children: _jsx("div", { style: { width: "100%", height: "100%", display: 'block', padding: "4px", position: 'relative' }, children: renderDcmtForm() }) })
1579
- : renderDcmtForm(), (showMoreInfoTaskPopup && showMoreInfoTaskTask && showMoreInfoTaskTask.id && handleNavigateToWGs && handleNavigateToDossiers && getAllTasks && deleteTaskByIdsCallback && addTaskCallback && editTaskCallback) && _jsx(TMTaskForm, { id: Number(showMoreInfoTaskTask.id), title: showMoreInfoTaskTask.name ?? 'N/A', formMode: FormModes.Update, onSaved: onSavedTaskFormCallback, editTaskCallback: editTaskCallback, onClose: () => { setShowMoreInfoTaskPopup(false); setShowMoreInfoTaskTask(undefined); }, onCancel: () => { setShowMoreInfoTaskPopup(false); setShowMoreInfoTaskTask(undefined); }, isModal: true, showBackButton: false, hasNavigation: false, width: taskModalSizes(deviceType, FormModes.Update).width, height: taskModalSizes(deviceType, FormModes.Update).height, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, visualizedTasks: [], currentTask: null, setCurrentTask: () => { }, selectedRowKeys: [], handleFocusedRowKeyChange: () => { }, onStatusChanged: () => { }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback })] }));
1702
+ : renderDcmtForm(), (showMoreInfoTaskPopup && showMoreInfoTaskTask && showMoreInfoTaskTask.id && handleNavigateToWGs && handleNavigateToDossiers && getAllTasks && deleteTaskByIdsCallback && addTaskCallback && editTaskCallback) && _jsx(TMTaskForm, { id: Number(showMoreInfoTaskTask.id), title: showMoreInfoTaskTask.name ?? 'N/A', formMode: FormModes.Update, onSaved: onSavedTaskFormCallback, editTaskCallback: editTaskCallback, onClose: () => { setShowMoreInfoTaskPopup(false); setShowMoreInfoTaskTask(undefined); }, onCancel: () => { setShowMoreInfoTaskPopup(false); setShowMoreInfoTaskTask(undefined); }, isModal: true, showBackButton: false, hasNavigation: false, width: taskModalSizes(deviceType, FormModes.Update).width, height: taskModalSizes(deviceType, FormModes.Update).height, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, visualizedTasks: [], currentTask: null, setCurrentTask: () => { }, selectedRowKeys: [], handleFocusedRowKeyChange: () => { }, onStatusChanged: () => { }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback }), (showMultiDetailArchiveModal && fromDTD && multiDetailMasterDcmts.length > 0) &&
1703
+ _jsx(TMMultiMasterDetailDcmtsForm, { dtd: fromDTD, masterDcmt: multiDetailMasterDcmts[0], onClose: () => { setShowMultiDetailArchiveModal(false); setMultiDetailMasterDcmts([]); }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, showDcmtFormSidebar: showDcmtFormSidebar, showTodoDcmtForm: showTodoDcmtForm, openFileUploaderPdfEditor: openFileUploaderPdfEditor, graphometricManager: graphometricManager, editPdfForm: editPdfForm, openS4TViewer: openS4TViewer, fetchRemoteCertificates: fetchRemoteCertificates, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onOpenPdfEditorRequest: onOpenPdfEditorRequest, onReferenceClick: onReferenceClick, onTaskCreateRequest: onTaskCreateRequest })] }));
1580
1704
  };
1581
1705
  export default TMDcmtForm;
1582
1706
  /**
@@ -1619,6 +1743,8 @@ export const validateMetadataList = (mvdList = []) => {
1619
1743
  if (isValidForValidation(mvd)) {
1620
1744
  validateRequiredField(mvd, value, validationItems);
1621
1745
  validateMaxLength(mvd, value, validationItems);
1746
+ validateCustomRegEx(mvd, value, validationItems);
1747
+ validateFormatRegEx(mvd, value, validationItems);
1622
1748
  }
1623
1749
  return validationItems;
1624
1750
  }, []);
@@ -1641,8 +1767,58 @@ const validateMaxLength = (mvd, value, validationItems) => {
1641
1767
  const isTextOrNumber = mvd.md?.dataType === MetadataDataTypes.Varchar || mvd.md?.dataType === MetadataDataTypes.Number;
1642
1768
  const isFormula = FormulaHelper.isFormula(value);
1643
1769
  if (isTextOrNumber && !isFormula && mvd.md?.length && value.replace(regex, '').length > maxLength) {
1644
- const message = `"${mvd.md.nameLoc ?? "no-name"}" ha superata massimo lunghezza di ${maxLength} caratteri.`;
1645
- validationItems.push(new ValidationItem(ResultTypes.ERROR, mvd.md.nameLoc ?? "", message));
1770
+ const fieldName = mvd.md?.nameLoc ?? mvd.md?.name ?? SDKUI_Localizator.Field;
1771
+ const message = SDKUI_Localizator.MaxLengthExceeded.replaceParams(fieldName, maxLength);
1772
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, fieldName, message));
1773
+ }
1774
+ };
1775
+ const validateCustomRegEx = (mvd, value, validationItems) => {
1776
+ const pattern = mvd.md?.format?.formatCustom;
1777
+ if (mvd.md?.format?.format !== MetadataFormats.CustomRegEx || !pattern)
1778
+ return;
1779
+ // Valore vuoto: ci pensa validateRequiredField; formule: non validabili con regex
1780
+ if (!value.trim() || FormulaHelper.isFormula(value))
1781
+ return;
1782
+ try {
1783
+ const regex = new RegExp(`^(?:${pattern})$`);
1784
+ if (!regex.test(value)) {
1785
+ const fieldName = mvd.md?.nameLoc ?? mvd.md?.name ?? SDKUI_Localizator.Field;
1786
+ const message = SDKUI_Localizator.FormatNotRespected.replaceParams(fieldName, pattern);
1787
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, fieldName, message));
1788
+ }
1789
+ }
1790
+ catch {
1791
+ // Pattern regex non valido: nessuna validazione, accetta qualsiasi valore
1792
+ }
1793
+ };
1794
+ // Regex predefinite per i formati standard (EMail, Partita IVA, Codice Fiscale)
1795
+ const FORMAT_REGEX_RULES = [
1796
+ {
1797
+ format: MetadataFormats.EMail,
1798
+ regex: /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/,
1799
+ message: (name) => SDKUI_Localizator.InvalidEmailAddress.replaceParams(name)
1800
+ },
1801
+ {
1802
+ format: MetadataFormats.PartitaIva,
1803
+ regex: /^[0-9]{11}$/,
1804
+ message: (name) => SDKUI_Localizator.InvalidVatNumber.replaceParams(name)
1805
+ },
1806
+ {
1807
+ // Persone fisiche (16 caratteri, incluse le lettere di omocodia) o soggetti giuridici (11 cifre)
1808
+ format: MetadataFormats.CodiceFiscale,
1809
+ regex: /^(?:[A-Z]{6}[0-9LMNPQRSTUV]{2}[ABCDEHLMPRST][0-9LMNPQRSTUV]{2}[A-Z][0-9LMNPQRSTUV]{3}[A-Z]|[0-9]{11})$/i,
1810
+ message: (name) => SDKUI_Localizator.InvalidTaxCode.replaceParams(name)
1811
+ }
1812
+ ];
1813
+ const validateFormatRegEx = (mvd, value, validationItems) => {
1814
+ const rule = FORMAT_REGEX_RULES.find(r => r.format === mvd.md?.format?.format);
1815
+ if (!rule)
1816
+ return;
1817
+ // Valore vuoto: ci pensa validateRequiredField; formule: non validabili con regex
1818
+ if (!value.trim() || FormulaHelper.isFormula(value))
1819
+ return;
1820
+ if (!rule.regex.test(value)) {
1821
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, mvd.md?.nameLoc ?? "", rule.message(mvd.md?.nameLoc ?? SDKUI_Localizator.Field)));
1646
1822
  }
1647
1823
  };
1648
1824
  //#endregion Validation
@@ -1667,6 +1843,8 @@ const PanelDisabledStateHandler = ({ isWFDisabled, isSysMetadataDisabled, isBoar
1667
1843
  setToolbarButtonDisabled('tmBlog', false);
1668
1844
  }
1669
1845
  }, [isBoardDisabled]);
1846
+ // Tracks whether tmWF has already been restored from the persisted state
1847
+ const didRestoreWF = useRef(false);
1670
1848
  useEffect(() => {
1671
1849
  if (isWFDisabled) {
1672
1850
  setToolbarButtonDisabled('tmWF', true);
@@ -1675,7 +1853,8 @@ const PanelDisabledStateHandler = ({ isWFDisabled, isSysMetadataDisabled, isBoar
1675
1853
  else {
1676
1854
  setToolbarButtonDisabled('tmWF', false);
1677
1855
  // Restore persisted visibility when WF becomes enabled
1678
- if (persistedWFVisible) {
1856
+ if (persistedWFVisible && !didRestoreWF.current) {
1857
+ didRestoreWF.current = true;
1679
1858
  setPanelVisibilityById('tmWF', true);
1680
1859
  }
1681
1860
  }
@@ -2,9 +2,20 @@ import React from "react";
2
2
  import { DcmtTypeDescriptor, TaskDescriptor, ObjectRef } from "@topconsultnpm/sdk-ts";
3
3
  import { IWorkItemData } from "../../../ts";
4
4
  import { DeviceType } from "../../base/TMDeviceProvider";
5
+ import { CaseFlowDcmtWorkItem } from "../../../hooks/useCaseFlowApprove";
5
6
  interface TMDcmtFormActionButtonsProps {
6
7
  showToppyForApprove: boolean;
7
8
  workItems: Array<IWorkItemData>;
9
+ /** Attività delle PRATICHE (CaseFlow) pendenti su QUESTO documento. */
10
+ caseFlowWorkItems?: Array<CaseFlowDcmtWorkItem>;
11
+ /**
12
+ * Completa l'attività di pratica. NON usato per la FIRMA: là si apre il viewer
13
+ * di firma ed è quello, a firma riuscita, a completare — esattamente come per
14
+ * i work item del workflow.
15
+ */
16
+ onCompleteCaseFlowWorkItem?: (item: CaseFlowDcmtWorkItem, comment?: string) => Promise<void>;
17
+ /** Rifiuta l'attività di pratica con un motivo. */
18
+ onRejectCaseFlowWorkItem?: (item: CaseFlowDcmtWorkItem, reason: string) => Promise<void>;
8
19
  deviceType: DeviceType | undefined;
9
20
  isMobile: boolean;
10
21
  handleSignApprove: () => void;