@topconsultnpm/sdkui-react 6.22.0-dev2.8 → 6.22.0-dev3.10

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 (311) hide show
  1. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +3 -3
  2. package/lib/components/NewComponents/ContextMenu/hooks.d.ts +1 -1
  3. package/lib/components/NewComponents/ContextMenu/styles.d.ts +14 -14
  4. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +6 -6
  5. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +35 -35
  6. package/lib/components/base/Styled.d.ts +5 -5
  7. package/lib/components/base/Styled.js +7 -5
  8. package/lib/components/base/TMAccordionNew.js +7 -7
  9. package/lib/components/base/TMAlert.d.ts +32 -32
  10. package/lib/components/base/TMAreaManager.js +1 -1
  11. package/lib/components/base/TMButton.js +4 -4
  12. package/lib/components/base/TMClosableList.js +3 -3
  13. package/lib/components/base/TMCounterBar.d.ts +2 -2
  14. package/lib/components/base/TMCounterContainer.d.ts +1 -2
  15. package/lib/components/base/TMCustomButton.d.ts +1 -1
  16. package/lib/components/base/TMCustomButton.js +1 -1
  17. package/lib/components/base/TMDataGrid.d.ts +4 -0
  18. package/lib/components/base/TMDataGrid.js +292 -12
  19. package/lib/components/base/TMDataGridExportForm.d.ts +1 -2
  20. package/lib/components/base/TMDropDownMenu.js +1 -1
  21. package/lib/components/base/TMEditorBase.d.ts +2 -0
  22. package/lib/components/base/TMFileManager.d.ts +1 -2
  23. package/lib/components/base/TMFileManager.js +5 -3
  24. package/lib/components/base/TMFileManagerDataGridView.d.ts +1 -2
  25. package/lib/components/base/TMFileManagerDataGridView.js +12 -3
  26. package/lib/components/base/TMFileManagerThumbnailItems.d.ts +1 -1
  27. package/lib/components/base/TMFileManagerThumbnailItems.js +20 -10
  28. package/lib/components/base/TMFileManagerThumbnailsView.d.ts +1 -1
  29. package/lib/components/base/TMFileManagerUtils.d.ts +4 -2
  30. package/lib/components/base/TMFileManagerUtils.js +37 -1
  31. package/lib/components/base/TMLayout.d.ts +6 -6
  32. package/lib/components/base/TMLayout.js +3 -3
  33. package/lib/components/base/TMList.d.ts +1 -2
  34. package/lib/components/base/TMList.js +1 -1
  35. package/lib/components/base/TMListView.d.ts +1 -1
  36. package/lib/components/base/TMListView.js +3 -3
  37. package/lib/components/base/TMModal.d.ts +11 -0
  38. package/lib/components/base/TMModal.js +47 -13
  39. package/lib/components/base/TMPanel.d.ts +6 -0
  40. package/lib/components/base/TMPanel.js +141 -28
  41. package/lib/components/base/TMPopUp.js +5 -2
  42. package/lib/components/base/TMResizableMenu.js +2 -2
  43. package/lib/components/base/TMRightSidebar.js +1 -1
  44. package/lib/components/base/TMShowAllOrMaxItemsButton.js +1 -1
  45. package/lib/components/base/TMSpinner.d.ts +1 -2
  46. package/lib/components/base/TMSpinner.js +2 -2
  47. package/lib/components/base/TMTab.d.ts +3 -4
  48. package/lib/components/base/TMTab.js +2 -2
  49. package/lib/components/base/TMTabControl.d.ts +101 -0
  50. package/lib/components/base/TMTabControl.js +653 -0
  51. package/lib/components/base/TMToggleButton.js +2 -2
  52. package/lib/components/base/TMToolbarCard.js +3 -3
  53. package/lib/components/base/TMTooltip.d.ts +2 -1
  54. package/lib/components/base/TMTooltip.js +24 -8
  55. package/lib/components/base/TMTreeView.d.ts +1 -1
  56. package/lib/components/base/TMTreeView.js +123 -70
  57. package/lib/components/base/TMUserAvatar.d.ts +1 -2
  58. package/lib/components/base/TMVilViewer.d.ts +1 -2
  59. package/lib/components/base/TMWaitPanel.d.ts +2 -3
  60. package/lib/components/base/TMWaitPanel.js +2 -2
  61. package/lib/components/choosers/TMCultureIDPicker.js +2 -2
  62. package/lib/components/choosers/TMDataListItemChooser.js +1 -1
  63. package/lib/components/choosers/TMDataListItemPicker.js +2 -2
  64. package/lib/components/choosers/TMDcmtTypeChooser.js +5 -4
  65. package/lib/components/choosers/TMDiskChooser.js +1 -1
  66. package/lib/components/choosers/TMDistinctValues.d.ts +9 -7
  67. package/lib/components/choosers/TMDistinctValues.js +157 -141
  68. package/lib/components/choosers/TMDynDataListItemChooser.d.ts +1 -1
  69. package/lib/components/choosers/TMDynDataListItemChooser.js +1 -1
  70. package/lib/components/choosers/TMImageIDChooser.js +1 -1
  71. package/lib/components/choosers/TMInvoiceRetrieveFormats.d.ts +1 -2
  72. package/lib/components/choosers/TMMetadataChooser.js +3 -3
  73. package/lib/components/choosers/TMOrderRetrieveFormats.d.ts +1 -2
  74. package/lib/components/choosers/TMQuickSearchInfo.d.ts +12 -0
  75. package/lib/components/choosers/TMQuickSearchInfo.js +279 -0
  76. package/lib/components/choosers/TMQuickSearchSettingsForm.d.ts +16 -0
  77. package/lib/components/choosers/TMQuickSearchSettingsForm.js +94 -0
  78. package/lib/components/choosers/TMRelationChooser.d.ts +3 -3
  79. package/lib/components/choosers/TMRelationChooser.js +1 -1
  80. package/lib/components/choosers/TMSelectedValuesSummary.d.ts +13 -0
  81. package/lib/components/choosers/TMSelectedValuesSummary.js +89 -0
  82. package/lib/components/choosers/TMUserChooser.d.ts +2 -2
  83. package/lib/components/choosers/TMUserChooser.js +1 -1
  84. package/lib/components/editors/TMCheckBox.js +1 -1
  85. package/lib/components/editors/TMDropDown.d.ts +3 -0
  86. package/lib/components/editors/TMDropDown.js +197 -5
  87. package/lib/components/editors/TMEditorStyled.d.ts +10 -10
  88. package/lib/components/editors/TMFormulaEditor.d.ts +1 -1
  89. package/lib/components/editors/TMFormulaEditor.js +1 -1
  90. package/lib/components/editors/TMHtmlContentDisplay.d.ts +1 -2
  91. package/lib/components/editors/TMHtmlContentDisplay.js +1 -1
  92. package/lib/components/editors/TMHtmlEditor.d.ts +1 -2
  93. package/lib/components/editors/TMLocalizedTextBox.js +1 -1
  94. package/lib/components/editors/TMMetadataEditor.d.ts +5 -1
  95. package/lib/components/editors/TMMetadataEditor.js +8 -3
  96. package/lib/components/editors/TMMetadataValues.js +6 -6
  97. package/lib/components/editors/TMRadioButton.js +2 -2
  98. package/lib/components/editors/TMSummary.js +3 -3
  99. package/lib/components/editors/TMTextArea.js +3 -3
  100. package/lib/components/editors/TMTextBox.js +3 -3
  101. package/lib/components/editors/TMTextExpression.js +1 -1
  102. package/lib/components/editors/TMTreeDropDown.d.ts +1 -1
  103. package/lib/components/features/archive/TMArchive.js +17 -3
  104. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.d.ts +1 -1
  105. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.js +2 -2
  106. package/lib/components/features/assistant/TMToppySpeechBubble.js +1 -1
  107. package/lib/components/features/blog/TMBlogCommentForm.d.ts +1 -2
  108. package/lib/components/features/documents/TMBatchUpdateForm.js +20 -6
  109. package/lib/components/features/documents/TMCopyToFolderForm.js +61 -22
  110. package/lib/components/features/documents/TMDcmtBlog.d.ts +3 -0
  111. package/lib/components/features/documents/TMDcmtBlog.js +4 -4
  112. package/lib/components/features/documents/TMDcmtForm.d.ts +7 -0
  113. package/lib/components/features/documents/TMDcmtForm.js +181 -54
  114. package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +12 -1
  115. package/lib/components/features/documents/TMDcmtFormActionButtons.js +79 -9
  116. package/lib/components/features/documents/TMDcmtIcon.d.ts +1 -2
  117. package/lib/components/features/documents/TMDcmtIcon.js +5 -3
  118. package/lib/components/features/documents/TMDcmtPreview.d.ts +1 -1
  119. package/lib/components/features/documents/TMDcmtPreview.js +12 -8
  120. package/lib/components/features/documents/TMDcmtTasks.d.ts +1 -2
  121. package/lib/components/features/documents/TMDownloadRelationViewerSection.js +1 -1
  122. package/lib/components/features/documents/TMDragDropOverlay.d.ts +1 -1
  123. package/lib/components/features/documents/TMFileUploader.js +3 -3
  124. package/lib/components/features/documents/TMMasterDetailDcmts.js +116 -34
  125. package/lib/components/features/documents/TMMasterInfoFields.d.ts +19 -0
  126. package/lib/components/features/documents/TMMasterInfoFields.js +184 -0
  127. package/lib/components/features/documents/TMMergeToPdfForm.d.ts +2 -4
  128. package/lib/components/features/documents/TMMergeToPdfForm.js +42 -10
  129. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +45 -0
  130. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +321 -0
  131. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +370 -0
  132. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.js +283 -0
  133. package/lib/components/features/documents/TMRelationViewer.d.ts +24 -3
  134. package/lib/components/features/documents/TMRelationViewer.js +110 -52
  135. package/lib/components/features/documents/copyAndMergeDcmtsShared.d.ts +1 -1
  136. package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +1 -2
  137. package/lib/components/features/search/TMMetadataOutputForm.d.ts +1 -2
  138. package/lib/components/features/search/TMMetadataOutputForm.js +1 -1
  139. package/lib/components/features/search/TMMetadataSorterForm.d.ts +1 -2
  140. package/lib/components/features/search/TMMetadataSorterForm.js +1 -1
  141. package/lib/components/features/search/TMSavedQuerySelector.d.ts +2 -2
  142. package/lib/components/features/search/TMSavedQuerySelector.js +2 -2
  143. package/lib/components/features/search/TMSearch.d.ts +1 -2
  144. package/lib/components/features/search/TMSearch.js +146 -21
  145. package/lib/components/features/search/TMSearchQueryEditor.js +7 -5
  146. package/lib/components/features/search/TMSearchQueryPanel.d.ts +4 -0
  147. package/lib/components/features/search/TMSearchQueryPanel.js +142 -68
  148. package/lib/components/features/search/TMSearchResult.d.ts +16 -0
  149. package/lib/components/features/search/TMSearchResult.js +439 -110
  150. package/lib/components/features/search/TMSearchResultFloatingActionButton.d.ts +1 -1
  151. package/lib/components/features/search/TMSignatureInfoContent.d.ts +1 -2
  152. package/lib/components/features/search/TMSignatureInfoContent.js +1 -1
  153. package/lib/components/features/search/TMTreeSelector.js +121 -70
  154. package/lib/components/features/search/TMViewHistoryDcmt.d.ts +1 -2
  155. package/lib/components/features/tasks/TMTaskForm.d.ts +1 -1
  156. package/lib/components/features/tasks/TMTaskForm.js +1 -1
  157. package/lib/components/features/tasks/TMTaskFormUtils.d.ts +10 -10
  158. package/lib/components/features/tasks/TMTaskFormUtils.js +3 -3
  159. package/lib/components/features/tasks/TMTasksAgenda.d.ts +1 -1
  160. package/lib/components/features/tasks/TMTasksAgenda.js +1 -1
  161. package/lib/components/features/tasks/TMTasksCalendar.d.ts +1 -1
  162. package/lib/components/features/tasks/TMTasksCalendar.js +1 -1
  163. package/lib/components/features/tasks/TMTasksHeader.d.ts +1 -1
  164. package/lib/components/features/tasks/TMTasksHeader.js +1 -1
  165. package/lib/components/features/tasks/TMTasksPanelContent.d.ts +1 -1
  166. package/lib/components/features/tasks/TMTasksUtilsView.d.ts +5 -5
  167. package/lib/components/features/tasks/TMTasksUtilsView.js +1 -1
  168. package/lib/components/features/tasks/TMTasksView.d.ts +1 -1
  169. package/lib/components/features/tasks/TMTasksView.js +7 -13
  170. package/lib/components/features/wg/TMWGsCopyMoveForm.d.ts +2 -3
  171. package/lib/components/features/wg/TMWGsCopyMoveForm.js +1 -1
  172. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +17 -8
  173. package/lib/components/features/workflow/TMWorkflowPopup.js +9 -5
  174. package/lib/components/features/workflow/diagram/ConnectionComponent.js +3 -3
  175. package/lib/components/features/workflow/diagram/DiagramItemComponent.js +3 -3
  176. package/lib/components/features/workflow/diagram/DiagramItemForm.js +1 -1
  177. package/lib/components/features/workflow/diagram/DiagramItemSvgContent.js +1 -1
  178. package/lib/components/features/workflow/diagram/RecipientList.js +1 -1
  179. package/lib/components/features/workflow/diagram/WFDiagram.js +4 -4
  180. package/lib/components/forms/Login/Chooser.d.ts +2 -2
  181. package/lib/components/forms/Login/Menu.js +1 -1
  182. package/lib/components/forms/Login/OTPReader.js +1 -1
  183. package/lib/components/forms/Login/PasswordStrengthChecker.js +1 -1
  184. package/lib/components/forms/Login/RapidAccessLogin.js +2 -2
  185. package/lib/components/forms/Login/RecoverPasswordFlow.js +2 -2
  186. package/lib/components/forms/Login/SelectBox.js +1 -1
  187. package/lib/components/forms/Login/StepIndicator.js +1 -1
  188. package/lib/components/forms/Login/TMLoginForm.js +7 -7
  189. package/lib/components/forms/Login/TextBox.js +1 -1
  190. package/lib/components/forms/TMApplyForm.js +3 -3
  191. package/lib/components/forms/TMChooserForm.d.ts +1 -2
  192. package/lib/components/forms/TMChooserForm.js +1 -1
  193. package/lib/components/forms/TMSaveForm.d.ts +4 -4
  194. package/lib/components/forms/TMSaveForm.js +3 -3
  195. package/lib/components/grids/TMBlogAttachments.d.ts +1 -2
  196. package/lib/components/grids/TMBlogAttachments.js +14 -3
  197. package/lib/components/grids/TMBlogHeader.d.ts +1 -1
  198. package/lib/components/grids/TMBlogHeader.js +5 -1
  199. package/lib/components/grids/TMBlogsPost.d.ts +3 -1
  200. package/lib/components/grids/TMBlogsPost.js +31 -4
  201. package/lib/components/grids/TMBlogsPostUtils.d.ts +10 -9
  202. package/lib/components/grids/TMBlogsPostUtils.js +15 -4
  203. package/lib/components/grids/TMRecentsManager.js +4 -4
  204. package/lib/components/grids/TMValidationItemsList.d.ts +1 -2
  205. package/lib/components/grids/TMValidationItemsList.js +1 -1
  206. package/lib/components/index.d.ts +2 -0
  207. package/lib/components/index.js +2 -0
  208. package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +2 -2
  209. package/lib/components/layout/panelManager/TMPanelManagerContainer.js +25 -15
  210. package/lib/components/layout/panelManager/TMPanelManagerContext.d.ts +2 -2
  211. package/lib/components/layout/panelManager/TMPanelManagerContext.js +68 -93
  212. package/lib/components/layout/panelManager/TMPanelManagerToolbar.d.ts +3 -3
  213. package/lib/components/layout/panelManager/TMPanelManagerToolbar.js +1 -1
  214. package/lib/components/layout/panelManager/TMPanelManagerWithPersistenceProvider.d.ts +2 -2
  215. package/lib/components/layout/panelManager/TMPanelWrapper.d.ts +2 -2
  216. package/lib/components/layout/panelManager/TMPanelWrapper.js +3 -3
  217. package/lib/components/layout/panelManager/types.d.ts +3 -0
  218. package/lib/components/layout/panelManager/utils.js +13 -11
  219. package/lib/components/pages/TMPage.d.ts +1 -1
  220. package/lib/components/pages/TMPage.js +1 -1
  221. package/lib/components/query/TMQueryCountButton.js +1 -1
  222. package/lib/components/query/TMQueryEditor.js +7 -7
  223. package/lib/components/settings/SettingsAppearance.d.ts +1 -2
  224. package/lib/components/sidebar/TMAboutApp.d.ts +1 -2
  225. package/lib/components/sidebar/TMCommandsPanel.js +1 -1
  226. package/lib/components/sidebar/TMHeader.d.ts +3 -3
  227. package/lib/components/sidebar/TMHeader.js +36 -26
  228. package/lib/components/sidebar/TMSidebar.js +1 -1
  229. package/lib/components/sidebar/TMSidebarItem.js +1 -1
  230. package/lib/components/viewers/TMDataListItemViewer.d.ts +2 -3
  231. package/lib/components/viewers/TMDataUserIdItemViewer.d.ts +2 -3
  232. package/lib/components/viewers/TMMidViewer.d.ts +2 -2
  233. package/lib/components/viewers/TMMidViewer.js +6 -3
  234. package/lib/components/viewers/TMTidViewer.d.ts +2 -2
  235. package/lib/components/viewers/TMTidViewer.js +89 -28
  236. package/lib/components/wizard/TMStepIndicator.js +3 -3
  237. package/lib/css/tm-sdkui.css +1 -1
  238. package/lib/devextreme-license.d.ts +1 -0
  239. package/lib/devextreme-license.js +3 -0
  240. package/lib/helper/Enum_Localizator.d.ts +4 -4
  241. package/lib/helper/Globalization.d.ts +1 -1
  242. package/lib/helper/SDKUI_Globals.d.ts +110 -0
  243. package/lib/helper/SDKUI_Globals.js +151 -0
  244. package/lib/helper/SDKUI_Localizator.d.ts +735 -687
  245. package/lib/helper/SDKUI_Localizator.js +480 -0
  246. package/lib/helper/TMAppUpdatedModal.d.ts +1 -0
  247. package/lib/helper/TMAppUpdatedModal.js +134 -0
  248. package/lib/helper/TMCommandsContextMenu.d.ts +1 -1
  249. package/lib/helper/TMIcons.d.ts +280 -279
  250. package/lib/helper/TMIcons.js +4 -3
  251. package/lib/helper/TMPdfViewer.d.ts +1 -2
  252. package/lib/helper/TMPdfViewer.js +1 -1
  253. package/lib/helper/TMToppyMessage.d.ts +2 -2
  254. package/lib/helper/TMToppyMessage.js +1 -1
  255. package/lib/helper/TMUtils.d.ts +14 -1
  256. package/lib/helper/TMUtils.js +25 -3
  257. package/lib/helper/checkinCheckoutManager.d.ts +1 -1
  258. package/lib/helper/checkinCheckoutManager.js +1 -1
  259. package/lib/helper/dataGridSearchHelper.d.ts +28 -0
  260. package/lib/helper/dataGridSearchHelper.js +51 -0
  261. package/lib/helper/dcmtsHelper.d.ts +20 -0
  262. package/lib/helper/dcmtsHelper.js +58 -1
  263. package/lib/helper/helpers.d.ts +13 -2
  264. package/lib/helper/helpers.js +27 -3
  265. package/lib/helper/index.d.ts +2 -0
  266. package/lib/helper/index.js +2 -0
  267. package/lib/helper/queryHelper.d.ts +6 -1
  268. package/lib/helper/queryHelper.js +8 -3
  269. package/lib/hooks/tmDistinctValuesGridHelper.d.ts +16 -0
  270. package/lib/hooks/tmDistinctValuesGridHelper.js +31 -0
  271. package/lib/hooks/useArchiveListForm.d.ts +39 -0
  272. package/lib/hooks/useArchiveListForm.js +46 -0
  273. package/lib/hooks/useCaseFlowApprove.d.ts +56 -0
  274. package/lib/hooks/useCaseFlowApprove.js +157 -0
  275. package/lib/hooks/useDataUserIdItem.d.ts +1 -0
  276. package/lib/hooks/useDataUserIdItem.js +1 -0
  277. package/lib/hooks/useDcmtOperations.d.ts +7 -0
  278. package/lib/hooks/useDcmtOperations.js +141 -71
  279. package/lib/hooks/useDocumentOperations.d.ts +4 -0
  280. package/lib/hooks/useDocumentOperations.js +53 -11
  281. package/lib/hooks/useInputDialog.d.ts +1 -2
  282. package/lib/hooks/useInputDialog.js +1 -1
  283. package/lib/hooks/useMultiMasterDetailDcmts.d.ts +113 -0
  284. package/lib/hooks/useMultiMasterDetailDcmts.js +760 -0
  285. package/lib/hooks/useQueryParametersDialog.js +1 -1
  286. package/lib/hooks/useRelatedDocuments.d.ts +1 -0
  287. package/lib/hooks/useRelatedDocuments.js +22 -27
  288. package/lib/hooks/useShowDossiersV5.d.ts +12 -0
  289. package/lib/hooks/useShowDossiersV5.js +37 -0
  290. package/lib/hooks/useTMDistinctValuesMetadataDisplay.d.ts +18 -0
  291. package/lib/hooks/useTMDistinctValuesMetadataDisplay.js +103 -0
  292. package/lib/hooks/useTMDistinctValuesQuickSearch.d.ts +49 -0
  293. package/lib/hooks/useTMDistinctValuesQuickSearch.js +307 -0
  294. package/lib/hooks/useTMDistinctValuesSelection.d.ts +42 -0
  295. package/lib/hooks/useTMDistinctValuesSelection.js +103 -0
  296. package/lib/hooks/useTMDistinctValuesSource.d.ts +29 -0
  297. package/lib/hooks/useTMDistinctValuesSource.js +105 -0
  298. package/lib/index.d.ts +2 -0
  299. package/lib/index.js +5 -2
  300. package/lib/services/caseflow/CaseFlowService.d.ts +247 -0
  301. package/lib/services/caseflow/CaseFlowService.js +720 -0
  302. package/lib/services/caseflow/CaseFlowTemplateCacheService.d.ts +28 -0
  303. package/lib/services/caseflow/CaseFlowTemplateCacheService.js +121 -0
  304. package/lib/services/caseflow/caseFlowNameCache.d.ts +32 -0
  305. package/lib/services/caseflow/caseFlowNameCache.js +116 -0
  306. package/lib/services/caseflow/caseFlowWorkItemUtils.d.ts +61 -0
  307. package/lib/services/caseflow/caseFlowWorkItemUtils.js +113 -0
  308. package/lib/services/index.d.ts +4 -0
  309. package/lib/services/index.js +4 -0
  310. package/lib/services/platform_services.d.ts +6 -7
  311. package/package.json +16 -13
@@ -1,13 +1,13 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
3
3
  import styled from 'styled-components';
4
4
  import { LoadIndicator } from 'devextreme-react';
5
5
  import { AppModules, DataColumnTypes, DataListViewModes, DcmtTypeListCacheService, LayoutCacheService, LayoutModes, MetadataDataDomains, SDK_Globals, SystemMIDsAsNumber, UserListCacheService, } from '@topconsultnpm/sdk-ts';
6
- import { deepCompare, formatDateTimeByMetadataFormat, formatNumberByMetadataFormat, generateUniqueColumnKeys, genUniqueId, getColumnFormatInfo, getSearchToolbarVisibility, IconAll, IconBoard, IconDcmtTypeSys, IconDelete, IconMenuVertical, IconPlatform, IconRefresh, IconSearchCheck, IconShow, isApprovalWorkflowView, isSign4TopEnabled, searchResultDescriptorToSimpleArray, searchResultToMetadataValues, SDKUI_Globals, SDKUI_Localizator } from '../../../helper';
6
+ import { customizeSearchByDisplayText, deepCompare, formatDateTimeByMetadataFormat, formatNumberByMetadataFormat, generateUniqueColumnKeys, genUniqueId, getColumnFormatInfo, getDateDisplayText, getNumberDisplayText, getSearchToolbarVisibility, IconAll, IconBoard, IconDcmtTypeSys, IconDelete, IconDuplicate, IconEdit, IconMenuVertical, IconPlatform, IconRefresh, IconSearchCheck, IconShow, isApprovalWorkflowView, isSign4TopEnabled, searchResultDescriptorToSimpleArray, searchResultToMetadataValues, SDKUI_Globals, SDKUI_Localizator, IconCloseOutline, getSearchResultPanelLayout, getSearchResultPanelLayoutSignature, hasSearchResultPanelLayout, saveSearchResultPanelLayout, subscribeSearchResultPanelLayout } from '../../../helper';
7
7
  import { CounterItemKey } from '../../base/TMCounterContainer';
8
8
  import { getDcmtCicoStatus } from '../../../helper/checkinCheckoutManager';
9
9
  import { DcmtOperationTypes, SearchResultContext, } from '../../../ts';
10
- import { Gutters } from '../../../utils/theme';
10
+ import { Gutters, TMColors } from '../../../utils/theme';
11
11
  import { useDataListItem } from '../../../hooks/useDataListItem';
12
12
  import { useDataUserIdItem } from '../../../hooks/useDataUserIdItem';
13
13
  import { getSelectedDcmtsOrFocused, useDocumentOperations } from '../../../hooks/useDocumentOperations';
@@ -23,7 +23,8 @@ import { StyledMultiViewPanel } from '../../base/Styled';
23
23
  import { TMLayoutWaitingContainer } from '../../base/TMWaitPanel';
24
24
  import TMMetadataValues from '../../editors/TMMetadataValues';
25
25
  import TMTidViewer from '../../viewers/TMTidViewer';
26
- import { TMPanelManagerProvider, useTMPanelManagerContext } from '../../layout/panelManager/TMPanelManagerContext';
26
+ import { useTMPanelManagerContext } from '../../layout/panelManager/TMPanelManagerContext';
27
+ import { TMPanelManagerWithPersistenceProvider } from '../../layout/panelManager/TMPanelManagerWithPersistenceProvider';
27
28
  import TMPanelManagerContainer from '../../layout/panelManager/TMPanelManagerContainer';
28
29
  import TMContextMenu from '../../NewComponents/ContextMenu/TMContextMenu';
29
30
  import TMToppyDraggableHelpCenter from '../assistant/TMToppyDraggableHelpCenter';
@@ -51,13 +52,25 @@ const orderByName = (array) => {
51
52
  return 1;
52
53
  } return 0; });
53
54
  };
55
+ //#endregion Helper Methods
56
+ /**
57
+ * Contesti che ricordano il layout dei pannelli, condividendone uno solo.
58
+ * Gli altri sono esclusi di proposito: FREE_SEARCH ha un pannello in più, quindi il suo layout non vale
59
+ * per gli altri, e i restanti mostrano il risultato dentro contenitori con esigenze di spazio loro.
60
+ */
61
+ const PERSISTED_LAYOUT_CONTEXTS = [
62
+ SearchResultContext.METADATA_SEARCH,
63
+ SearchResultContext.WORKFLOW_APPROVE,
64
+ ];
54
65
  const TMSearchResult = ({
55
66
  // Data
56
67
  groupId, searchResults = [], context = SearchResultContext.METADATA_SEARCH, title, selectedSearchResultTID, floatingActionConfig, workingGroupContext = undefined, inputDID,
57
68
  // Boolean flags to enable/disable features
58
- autoFocusFirstRow = true, formAutoOpen, isVisible = true, allowRelations = true, openDcmtFormAsModal = false, showSearchResultSidebar = true, showDcmtFormSidebar = true, showSelector = false, isClosable = false, allowFloatingBar = true, showToolbarHeader = true, showBackButton = true, disableAccordionIfSingleCategory = false, editPdfForm = false, openS4TViewer = false, showTodoDcmtForm = false, showToppyDraggableHelpCenter = true, toppyHelpCenterUsePortal = false, showNoDcmtFoundMessage = true, enablePinIcons = true,
69
+ autoFocusFirstRow = true, formAutoOpen, isVisible = true, allowRelations = true, openDcmtFormAsModal = false, showSearchResultSidebar = true, showDcmtFormSidebar = true, showSelector = false, isClosable = false, allowFloatingBar = true, showToolbarHeader = true, showBackButton = true, backCaption, showToolbarCloseButton = false, disableAccordionIfSingleCategory = false, editPdfForm = false, openS4TViewer = false, showTodoDcmtForm = false, showToppyDraggableHelpCenter = true, toppyHelpCenterUsePortal = false, showNoDcmtFoundMessage = true, enablePinIcons = true, showCounterConfig = true, showActionsColumn = false, compactPager = false, onRowDuplicateRequest,
70
+ // Counters
71
+ counterConfig,
59
72
  // Callbacks (optional)
60
- openInOffice, onRefreshAfterAddDcmtToFavs, onRefreshSearchAsyncDatagrid, onSelectedTIDChanged, onWFOperationCompleted, onClose, onFileOpened, onTaskCreateRequest, openWGsCopyMoveForm, openCommentFormCallback, openAddDocumentForm, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor, passToArchiveCallback, onReferenceClick,
73
+ openInOffice, onRefreshAfterAddDcmtToFavs, onRefreshSearchAsyncDatagrid, onSelectedTIDChanged, onSelectedTIDCleared, onWFOperationCompleted, onClose, onFileOpened, onTaskCreateRequest, openWGsCopyMoveForm, openCommentFormCallback, openAddDocumentForm, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor, passToArchiveCallback, onReferenceClick,
61
74
  // Tasks
62
75
  allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback,
63
76
  // Navigation
@@ -69,13 +82,19 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
69
82
  // Quando l'utente seleziona manualmente, il ref viene settato a false e il focus automatico
70
83
  // torna al comportamento normale.
71
84
  const isFirstAutoFocusRef = useRef(true);
85
+ // Mostra il pannello lista. È una ref perché il TMPanelManagerProvider sta dentro al JSX di
86
+ // questo componente, quindi qui il context non si può usare: la riempie ShowMainPanelBridge.
87
+ const showMainPanelRef = useRef(null);
72
88
  // ID state to force remount of components
73
89
  const [id, setID] = useState('');
74
90
  // Document type descriptor of the currently document
75
91
  const [fromDTD, setFromDTD] = useState();
76
92
  const [currentDcmt, setCurrentDcmt] = useState();
77
- // State to specify if the details form is open or not
78
- const [splitterSize, setSplitterSize] = useState(['100%', '0']);
93
+ // Passo corrente. Su mobile decide anche quale pannello è a schermo (vedi isSteppedLayout).
94
+ // 'auto' -> l'utente non ha ancora scelto: si può selezionare il primo tipo documento
95
+ // 'selector' -> è tornato indietro col back: non selezionare niente al posto suo
96
+ // 'results' -> è sulla griglia del tipo scelto
97
+ const [navStep, setNavStep] = useState('auto');
79
98
  // State to control the selected search result
80
99
  const [selectedSearchResult, setSelectedSearchResult] = useState();
81
100
  // State to control the search results to show in the datagrid
@@ -303,7 +322,7 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
303
322
  createTaskFromDocumentOrWorkItem();
304
323
  }
305
324
  };
306
- const { operationItems, renderFloatingBar, renderDcmtOperations, features, } = useDocumentOperations({
325
+ const { operationItems, selectedDcmtInfos, renderFloatingBar, renderDcmtOperations, features, } = useDocumentOperations({
307
326
  context: context,
308
327
  documentData: {
309
328
  dtd: fromDTD,
@@ -377,9 +396,69 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
377
396
  openTaskFormHandler,
378
397
  },
379
398
  });
380
- const { isOpenDcmtForm, openFormHandler, dcmtFormLayoutMode, onDcmtFormOpenChange, showSearchTMDatagrid, showExportForm, isOpenBatchUpdate, isModifiedBatchUpdate, updateBatchUpdateForm, closeDcmtFormHandler, handleSignApprove, checkoutInfo: { showCicoWaitPanel, cicoWaitPanelTitle, showCicoPrimaryProgress, cicoPrimaryProgressText, cicoPrimaryProgressValue, cicoPrimaryProgressMax, }, dcmtOperations: { abortController, showWaitPanel, showPrimary, waitPanelTitle, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, runOperationAsync, }, relatedDocumentsInfo: { isOpenDetails, isOpenMaster, checkRelatedDcmtsArchiveCapability, checkManyToManyCapability, }, toppyOperations: { showApprovePopup, showRejectPopup, showReAssignPopup, showMoreInfoPopup, updateShowApprovePopup, updateShowRejectPopup, updateShowReAssignPopup, updateShowMoreInfoPopup } } = features;
399
+ const { isOpenDcmtForm, isDcmtFormModal, openFormHandler, dcmtFormLayoutMode, onDcmtFormOpenChange, showSearchTMDatagrid, showDcmtTypesSelection, showExportForm, updateBatchUpdateForm, closeDcmtFormHandler, handleSignApprove, checkoutInfo: { showCicoWaitPanel, cicoWaitPanelTitle, showCicoPrimaryProgress, cicoPrimaryProgressText, cicoPrimaryProgressValue, cicoPrimaryProgressMax, }, dcmtOperations: { abortController, showWaitPanel, showPrimary, waitPanelTitle, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, runOperationAsync, }, relatedDocumentsInfo: { isOpenDetails, isOpenMaster, checkRelatedDcmtsArchiveCapability, checkManyToManyCapability, }, toppyOperations: { showApprovePopup, showRejectPopup, showReAssignPopup, showMoreInfoPopup, updateShowApprovePopup, updateShowRejectPopup, updateShowReAssignPopup, updateShowMoreInfoPopup } } = features;
400
+ // ----- Azioni della colonna di riga (showActionsColumn) -----------------------------------------
401
+ // Le voci di operationItems agiscono sui documenti selezionati o, in mancanza, su quello a fuoco:
402
+ // non accettano una riga come argomento. Il click sull'icona quindi azzera la selezione e porta il
403
+ // fuoco sulla riga cliccata, poi attende. L'attesa non è sul fuoco ma su selectedDcmtInfos, che
404
+ // l'hook ricalcola in un effect (un render più tardi): lanciare l'operazione prima significherebbe
405
+ // eseguirla sulla riga precedente.
406
+ const pendingRowActionRef = useRef(undefined);
407
+ // La callback è letta da una ref: dipendere dal prop renderebbe nuova requestRowAction, e con essa
408
+ // la colonna delle azioni, a ogni render del padre (vedi actionsColumn in TMSearchResultGrid)
409
+ const onRowDuplicateRequestRef = useRef(onRowDuplicateRequest);
410
+ onRowDuplicateRequestRef.current = onRowDuplicateRequest;
411
+ const requestRowAction = useCallback((operationId, rowData) => {
412
+ if (!showActionsColumn)
413
+ return;
414
+ if (rowData?.TID === undefined || rowData?.DID === undefined) {
415
+ ShowAlert({ message: SDKUI_Localizator.InvalidDcmt, mode: "warning", duration: 3000 });
416
+ return;
417
+ }
418
+ // Duplica ridefinita dal chiamante: agisce sulla riga cliccata, senza toccare fuoco e selezione
419
+ if (operationId === 'dup' && onRowDuplicateRequestRef.current) {
420
+ onRowDuplicateRequestRef.current(rowData);
421
+ return;
422
+ }
423
+ pendingRowActionRef.current = { operationId, TID: rowData.TID, DID: rowData.DID };
424
+ isFirstAutoFocusRef.current = false;
425
+ setSelectedItems([]);
426
+ setFocusedItem(rowData);
427
+ }, [showActionsColumn]);
428
+ // La richiesta viene scartata se il documento sparisce dai risultati (es. refresh dopo
429
+ // un'eliminazione): senza questo resterebbe appesa e partirebbe al prossimo cambio di fuoco.
430
+ useEffect(() => { pendingRowActionRef.current = undefined; }, [selectedSearchResult, lastUpdateSearchTime]);
431
+ useEffect(() => {
432
+ if (!showActionsColumn)
433
+ return;
434
+ const pending = pendingRowActionRef.current;
435
+ if (!pending)
436
+ return;
437
+ // L'hook non ha ancora recepito la riga richiesta: si riproverà al prossimo aggiornamento
438
+ if (selectedDcmtInfos.length !== 1)
439
+ return;
440
+ if (selectedDcmtInfos[0].TID !== pending.TID || selectedDcmtInfos[0].DID !== pending.DID)
441
+ return;
442
+ pendingRowActionRef.current = undefined;
443
+ const operation = findOperationItemById(operationItems, pending.operationId);
444
+ // Ora che il fuoco è sulla riga, `disabled` riflette i permessi per quel documento
445
+ if (!operation || operation.disabled || operation.visible === false)
446
+ return;
447
+ operation.onClick?.();
448
+ }, [showActionsColumn, selectedDcmtInfos, operationItems]);
381
449
  const deviceType = useDeviceType();
382
450
  const isMobile = deviceType === DeviceType.MOBILE;
451
+ const hasSingleDcmtType = currentSearchResults.length === 1;
452
+ // Su mobile si vede un pannello per volta; su desktop selettore e griglia sono affiancati
453
+ const isSteppedLayout = showSelector && isMobile;
454
+ // Un solo tipo documento su desktop: non c'è niente da scegliere, quindi il selettore sparisce
455
+ // (larghezza 0, nessun separatore) e lo spazio va tutto alla griglia. Il menu "Altro" permette
456
+ // di riaprirlo (vedi canToggleDcmtTypesSelection nell'hook).
457
+ const isSelectorCollapsed = showSelector && !isSteppedLayout && hasSingleDcmtType && !showDcmtTypesSelection;
458
+ // Senza selettore lo spazio va tutto alla griglia; altrimenti a step su mobile, affiancati su desktop
459
+ const splitterSizes = (!showSelector || isSelectorCollapsed) ? ['0%', '100%']
460
+ : isSteppedLayout ? (navStep === 'results' ? ['0', '100%'] : ['100%', '0'])
461
+ : ['30%', '70%'];
383
462
  const selectedDocs = getSelectedDcmtsOrFocused(selectedItems, focusedItem);
384
463
  // Disable the "Sign/Approve" button if:
385
464
  // 1. No document or multiple documents are selected, OR
@@ -400,8 +479,14 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
400
479
  setSelectedSearchResult(undefined);
401
480
  return;
402
481
  }
482
+ // Un solo tipo documento: selezionalo e vai ai risultati, a meno che l'utente sia tornato indietro
403
483
  if (searchResults.length === 1) {
484
+ if (navStep === 'selector') {
485
+ setSelectedSearchResult(undefined);
486
+ return;
487
+ }
404
488
  setSelectedSearchResult(searchResults[0]);
489
+ setNavStep('results');
405
490
  return;
406
491
  }
407
492
  // Se il TID precedentemente selezionato esiste ancora nei nuovi risultati, mantienilo.
@@ -415,6 +500,11 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
415
500
  return;
416
501
  }
417
502
  }
503
+ // L'utente è sul selettore
504
+ if (isMobile && navStep !== 'results') {
505
+ setSelectedSearchResult(undefined);
506
+ return;
507
+ }
418
508
  // Altrimenti seleziona il primo risultato ordinato
419
509
  setSelectedSearchResult(orderByName(searchResults)[0]);
420
510
  }, [searchResults]);
@@ -471,7 +561,9 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
471
561
  return;
472
562
  if (focusedItem?.DID != inputDID)
473
563
  return;
474
- openFormHandler(LayoutModes.Update);
564
+ if (focusedItem?.TID === undefined)
565
+ return;
566
+ onDcmtFormOpenChange(true, LayoutModes.Update);
475
567
  }, [inputDID, formAutoOpen, focusedItem]);
476
568
  // Quando openS4TViewer è true, apri automaticamente il viewer S4T
477
569
  useEffect(() => {
@@ -531,47 +623,75 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
531
623
  let counters = (showSelector && disableAccordionIfSingleCategory && searchResults.length > 1) ? getSearchResultCountersSingleCategory(searchResults) : "";
532
624
  if (title)
533
625
  return title + counters;
534
- let titleHeader = 'Ricerca per metadati';
626
+ // Nome del tipo documento selezionato, accodato al titolo
627
+ const selectedDcmtTypeName = selectedSearchResult?.fromName ?? (searchResults?.length === 1 ? searchResults[0]?.fromName : undefined);
628
+ const withSelectedDcmtTypeName = (baseTitle) => selectedDcmtTypeName ? `${baseTitle} - ${selectedDcmtTypeName}` : baseTitle;
629
+ let titleHeader = withSelectedDcmtTypeName('Ricerca per metadati');
535
630
  switch (context) {
536
631
  case SearchResultContext.MASTER_DETAIL:
537
632
  case SearchResultContext.METADATA_SEARCH:
538
633
  titleHeader = `${searchResults?.length > 1 ? selectedSearchResult?.fromName ?? 'Ricerca per metadati' : searchResults[0]?.fromName ?? 'Ricerca per metadati'}`;
539
634
  break;
540
635
  case SearchResultContext.FAVORITES_AND_RECENTS:
541
- titleHeader = SDKUI_Localizator.FavoritesAndRecentDcmts;
636
+ titleHeader = withSelectedDcmtTypeName(SDKUI_Localizator.FavoritesAndRecentDcmts);
542
637
  break;
543
638
  case SearchResultContext.WORKFLOW_APPROVE:
544
- titleHeader = SDKUI_Localizator.WorkflowApproval;
639
+ titleHeader = withSelectedDcmtTypeName(SDKUI_Localizator.WorkflowApproval);
545
640
  break;
546
641
  case SearchResultContext.FREE_SEARCH:
547
- titleHeader = `Risultato della ricerca full text`;
642
+ titleHeader = withSelectedDcmtTypeName('Risultato della ricerca full text');
548
643
  break;
549
644
  }
550
645
  return titleHeader + counters;
551
646
  };
552
- const onBack = () => {
553
- if (isOpenBatchUpdate && isModifiedBatchUpdate) {
554
- TMMessageBoxManager.show({
555
- title: SDKUI_Localizator.Cancel, message: SDKUI_Localizator.ConfirmOnCancel, buttons: [ButtonNames.YES, ButtonNames.NO],
556
- onButtonClick: (e) => {
557
- if (e !== ButtonNames.YES)
558
- return;
559
- setSplitterSize(['100%', '0']);
560
- onClose?.();
561
- }
562
- });
563
- }
564
- else if (isOpenDcmtForm) {
565
- onDcmtFormOpenChange(false, LayoutModes.Update);
566
- }
567
- else {
568
- if (isMobile && currentSearchResults.length > 1) {
569
- setSelectedSearchResult(undefined);
570
- }
571
- setSplitterSize(['100%', '0']);
572
- onClose?.();
647
+ // Dai risultati si risale al selettore dei tipi documento
648
+ const canGoBackToSelector = isSteppedLayout && navStep === 'results' && selectedSearchResult !== undefined;
649
+ /**
650
+ * Back di tutti i pannelli (e X di chiusura se isClosable). Su mobile risale un livello alla volta:
651
+ * pannello secondario -> lista dei risultati -> selettore dei tipi documento -> uscita.
652
+ * Su desktop i pannelli sono affiancati, quindi resta solo l'uscita.
653
+ *
654
+ * @param fromSecondaryPanel - true se il back arriva da un pannello secondario
655
+ */
656
+ const onBack = useCallback((fromSecondaryPanel = false) => {
657
+ // Non è previsto nessun modo di uscire: non fare niente
658
+ if (!showBackButton && !isClosable)
659
+ return;
660
+ // Torna alla lista senza toccare gli stati: l'utente deve ritrovare la sua selezione
661
+ if (fromSecondaryPanel) {
662
+ showMainPanelRef.current?.();
663
+ return;
573
664
  }
574
- };
665
+ // Sia il ritorno al selettore sia l'uscita ripartono da una lista pulita
666
+ setSelectedSearchResult(undefined);
667
+ setFocusedItem(undefined);
668
+ setSelectedItems([]);
669
+ setSelectedRowKeysFromDataGrid([]);
670
+ setCurrentDcmt(undefined);
671
+ setCurrentMetadataValues([]);
672
+ setShowIndexingInfo(false);
673
+ isFirstAutoFocusRef.current = true;
674
+ // Il chiamante può tenere allineato il suo TID selezionato (es. selectedSearchResultTID)
675
+ onSelectedTIDCleared?.();
676
+ // [2] l'utente ha chiesto la lista: resta lì finché non sceglie lui, niente auto-selezione.
677
+ // [1] si esce: si riparte da capo, quindi l'auto-selezione torna permessa.
678
+ setNavStep(canGoBackToSelector ? 'selector' : 'auto');
679
+ // [2] C'è ancora un livello sopra: restiamo dentro, sul selettore
680
+ if (canGoBackToSelector)
681
+ return;
682
+ // [1] Si esce e si avvisa il chiamante
683
+ onClose?.();
684
+ }, [canGoBackToSelector, showBackButton, isClosable, onClose, onSelectedTIDCleared]);
685
+ /**
686
+ * Back del pannello lista. `undefined` = freccia non renderizzata, quindi la mostriamo solo se
687
+ * ha dove tornare: uno step intermedio, o un onClose per uscire. Con `isClosable` basta la X.
688
+ */
689
+ const backHandler = (showBackButton && !isClosable && (canGoBackToSelector || onClose !== undefined)) ? onBack : undefined;
690
+ /**
691
+ * Back dei pannelli secondari: la stessa onBack marcata come livello [3]. Solo su mobile:
692
+ * su desktop stanno affiancati alla lista e non c'è niente da cui tornare.
693
+ */
694
+ const backHandlerSecondary = useMemo(() => (isMobile && backHandler) ? () => backHandler(true) : undefined, [isMobile, backHandler]);
575
695
  const refreshDataGridAfterRemoveAsync = async () => {
576
696
  let index = selectedSearchResult?.dtdResult?.columns?.findIndex(col => col.caption === 'DID');
577
697
  let selectedRows = [];
@@ -603,21 +723,6 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
603
723
  return newResults;
604
724
  });
605
725
  };
606
- /**
607
- * Restituisce l'handler onBack per i pannelli, evitando duplicazione di codice.
608
- * @param isMainPanel - Se true, è il pannello principale dei risultati di ricerca
609
- */
610
- const getOnBackHandler = (isMainPanel = false) => {
611
- // Se showBackButton è false, non mostrare mai il back
612
- if (showBackButton === false)
613
- return undefined;
614
- // Mobile: mostra back su tutti i pannelli (se showBackButton è definito e non è closable)
615
- if (isMobile) {
616
- return (showBackButton !== undefined && !isClosable) ? onBack : undefined;
617
- }
618
- // Desktop: mostra back solo sul pannello principale dei risultati (se showBackButton è definito e non è closable)
619
- return (showBackButton !== undefined && isMainPanel && !isClosable) ? onBack : undefined;
620
- };
621
726
  const removeDcmtFromFavsOrRecents = async () => {
622
727
  switch (selectedSearchResult?.category) {
623
728
  case "Favorites":
@@ -634,9 +739,9 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
634
739
  };
635
740
  const onSearchResultSelectionChanged = (e) => {
636
741
  setSelectedSearchResult(e);
637
- if (deviceType === DeviceType.MOBILE) {
638
- setSplitterSize(['0', '100%']);
639
- }
742
+ // Scelto il tipo documento si passa ai risultati (a livello di layout è ignorato se i due
743
+ // step sono affiancati, ma vale comunque come "l'utente non è più fermo sul selettore")
744
+ setNavStep('results');
640
745
  onSelectedTIDChanged?.(e.fromTID);
641
746
  };
642
747
  const showToppyForApprove = useMemo(() => {
@@ -660,14 +765,15 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
660
765
  && !showTodoDcmtForm);
661
766
  }, [showToppyForApprove, showToppyDraggableHelpCenter, selectedDocs, showApprovePopup, showRejectPopup, showReAssignPopup, showMoreInfoPopup, editPdfForm, openS4TViewer, showTodoDcmtForm]);
662
767
  const searchResutlToolbar = _jsxs(_Fragment, { children: [context === SearchResultContext.FAVORITES_AND_RECENTS &&
663
- _jsx("div", { style: { display: 'flex', alignItems: 'center', gap: '5px' }, children: _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconDelete, { color: 'white' }), caption: "Rimuovi da " + (selectedSearchResult?.category === "Favorites" ? '"Preferiti"' : '"Recenti"'), disabled: getSelectedDcmtsOrFocused(selectedItems, focusedItem).length <= 0, onClick: removeDcmtFromFavsOrRecents }) }), _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconRefresh, { color: 'white' }), caption: SDKUI_Localizator.Refresh, onClick: onRefreshSearchAsyncDatagrid }), _jsx(TMContextMenu, { items: operationItems, trigger: "left", children: _jsx(IconMenuVertical, { color: 'white', cursor: 'pointer' }) })] });
768
+ _jsx("div", { style: { display: 'flex', alignItems: 'center', gap: '5px' }, children: _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconDelete, { color: 'white' }), caption: "Rimuovi da " + (selectedSearchResult?.category === "Favorites" ? '"Preferiti"' : '"Recenti"'), disabled: getSelectedDcmtsOrFocused(selectedItems, focusedItem).length <= 0, onClick: removeDcmtFromFavsOrRecents }) }), _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconRefresh, { color: 'white' }), caption: SDKUI_Localizator.Refresh, onClick: onRefreshSearchAsyncDatagrid }), _jsx(TMContextMenu, { items: operationItems, trigger: "left", children: _jsx(IconMenuVertical, { color: 'white', cursor: 'pointer' }) }), showToolbarCloseButton && onClose &&
769
+ _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconCloseOutline, { color: 'white' }), caption: SDKUI_Localizator.Close, onClick: onClose })] });
664
770
  const tmSearchResult = useMemo(() => (!searchResults || searchResults.length <= 0)
665
771
  ? _jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', width: '100%' }, children: [_jsx(IconBoard, { fontSize: 96 }), showNoDcmtFoundMessage && _jsx("div", { style: { fontSize: "15px", marginTop: "10px" }, children: SDKUI_Localizator.NoDcmtFound }), openAddDocumentForm && _jsx("div", { style: { marginTop: "10px" }, children: _jsx(TMButton, { fontSize: "15px", icon: _jsx("i", { className: 'dx-icon-share' }), caption: SDKUI_Localizator.Share, onClick: openAddDocumentForm }) })] })
666
772
  :
667
- _jsxs(_Fragment, { children: [_jsxs(TMLayoutItem, { height: '100%', children: [_jsxs("div", { ref: floatingBarContainerRef, style: { position: 'relative', height: '100%', width: '100%' }, children: [_jsxs(TMSplitterLayout, { direction: 'horizontal', overflow: 'visible', separatorSize: Gutters.getGutters(), separatorActiveColor: 'transparent', separatorColor: 'transparent', min: ['0', '0'], showSeparator: showSelector && deviceType !== DeviceType.MOBILE, start: showSelector ? deviceType !== DeviceType.MOBILE ? ['30%', '70%'] : splitterSize : ['0%', '100%'], children: [showSelector ?
668
- _jsx(TMLayoutItem, { children: _jsx(TMSearchResultSelector, { searchResults: currentSearchResults, disableAccordionIfSingleCategory: disableAccordionIfSingleCategory, selectedTID: selectedSearchResultTID, selectedSearchResult: selectedSearchResult, autoSelectFirst: !isMobile || currentSearchResults.length === 1, onSelectionChanged: onSearchResultSelectionChanged }) })
773
+ _jsxs(_Fragment, { children: [_jsxs(TMLayoutItem, { height: '100%', children: [_jsxs("div", { ref: floatingBarContainerRef, style: { position: 'relative', height: '100%', width: '100%' }, children: [_jsxs(TMSplitterLayout, { direction: 'horizontal', overflow: 'visible', separatorSize: Gutters.getGutters(), separatorActiveColor: 'transparent', separatorColor: 'transparent', min: ['0', '0'], showSeparator: showSelector && !isSteppedLayout && !isSelectorCollapsed, start: splitterSizes, children: [showSelector ?
774
+ _jsx(TMLayoutItem, { children: _jsx(TMSearchResultSelector, { searchResults: currentSearchResults, disableAccordionIfSingleCategory: disableAccordionIfSingleCategory, selectedTID: selectedSearchResultTID, selectedSearchResult: selectedSearchResult, autoSelectFirst: !isMobile || hasSingleDcmtType, onSelectionChanged: onSearchResultSelectionChanged }) })
669
775
  :
670
- _jsx(_Fragment, {}), _jsx(TMLayoutItem, { children: _jsx(TMSearchResultGrid, { openInOffice: openInOffice, fromDTD: fromDTD, operationItems: operationItems, allUsers: allUsers, inputFocusedItem: focusedItem, inputSelectedItems: selectedItems, showExportForm: showExportForm, onFocusedItemChanged: handleFocusedItemChangedFromGrid, onDownloadDcmtsAsync: async (inputDcmts, downloadType, downloadMode, _y, confirmAttachments) => await downloadDcmtsAsync({ inputDcmts, downloadType, downloadMode, onFileDownloaded: onFileOpened, confirmAttachments }), lastUpdateSearchTime: lastUpdateSearchTime, searchResult: searchResults.length > 1 ? selectedSearchResult : searchResults[0], onSelectionChanged: (items) => { setSelectedItems(items); }, onDblClick: () => openFormHandler(LayoutModes.Update), showSearchTMDatagrid: showSearchTMDatagrid, onVisibleItemChanged: setVisibleItems, updateDataColumnsFromDataGrid: updateDataColumnsFromDataGrid, updateDataSourceFromDataGrid: updateDataSourceFromDataGrid, updateSelectedRowKeysFromDataGrid: updateSelectedRowKeysFromDataGrid, disableAutoFocus: autoFocusFirstRow === false && isFirstAutoFocusRef.current, dcmtsReturned: dcmtsReturned, dcmtsFound: dcmtsFound }) })] }), renderFloatingBar] }), _jsx(TMToppyDraggableHelpCenter, { usePortal: toppyHelpCenterUsePortal, isVisible: isToppyHelpCenterVisible, content: _jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, children: _jsx(WorkFlowOperationButtons, { dtd: fromDTD, deviceType: deviceType, onApprove: () => {
776
+ _jsx(_Fragment, {}), _jsx(TMLayoutItem, { children: _jsx(TMSearchResultGrid, { openInOffice: openInOffice, fromDTD: fromDTD, operationItems: operationItems, allUsers: allUsers, inputFocusedItem: focusedItem, inputSelectedItems: selectedItems, showExportForm: showExportForm, onFocusedItemChanged: handleFocusedItemChangedFromGrid, onDownloadDcmtsAsync: async (inputDcmts, downloadType, downloadMode, _y, confirmAttachments) => await downloadDcmtsAsync({ inputDcmts, downloadType, downloadMode, onFileDownloaded: onFileOpened, confirmAttachments }), lastUpdateSearchTime: lastUpdateSearchTime, searchResult: searchResults.length > 1 ? selectedSearchResult : searchResults[0], onSelectionChanged: (items) => { setSelectedItems(items); }, onDblClick: () => openFormHandler(LayoutModes.Update), showSearchTMDatagrid: showSearchTMDatagrid, onVisibleItemChanged: setVisibleItems, updateDataColumnsFromDataGrid: updateDataColumnsFromDataGrid, updateDataSourceFromDataGrid: updateDataSourceFromDataGrid, updateSelectedRowKeysFromDataGrid: updateSelectedRowKeysFromDataGrid, disableAutoFocus: autoFocusFirstRow === false && isFirstAutoFocusRef.current, dcmtsReturned: dcmtsReturned, dcmtsFound: dcmtsFound, showCounterConfig: showCounterConfig, counterConfig: counterConfig, showActionsColumn: showActionsColumn, compactPager: compactPager, onRowActionRequest: requestRowAction }) })] }), renderFloatingBar] }), _jsx(TMToppyDraggableHelpCenter, { usePortal: toppyHelpCenterUsePortal, isVisible: isToppyHelpCenterVisible, content: _jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, children: _jsx(WorkFlowOperationButtons, { dtd: fromDTD, deviceType: deviceType, onApprove: () => {
671
777
  updateShowApprovePopup(true);
672
778
  }, onSignApprove: () => {
673
779
  handleSignApprove();
@@ -687,7 +793,6 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
687
793
  showApprovePopup,
688
794
  showRejectPopup,
689
795
  showReAssignPopup,
690
- isOpenBatchUpdate,
691
796
  isOpenDetails,
692
797
  isOpenMaster,
693
798
  isOpenDcmtForm,
@@ -698,6 +803,10 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
698
803
  openS4TViewer,
699
804
  showBackButton,
700
805
  isMobile,
806
+ navStep,
807
+ isSteppedLayout,
808
+ isSelectorCollapsed,
809
+ currentSearchResults,
701
810
  currentMetadataValues,
702
811
  onRefreshSearchAsyncDatagrid,
703
812
  handleNavigateToWGs,
@@ -705,9 +814,14 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
705
814
  editPdfForm,
706
815
  showNoDcmtFoundMessage
707
816
  ]);
708
- const tmBlog = useMemo(() => _jsx(TMDcmtBlog, { tid: focusedItem?.TID, did: focusedItem?.DID, fetchBlogDataTrigger: refreshBlogTrigger, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), [focusedItem, allTasks, refreshBlogTrigger, handleNavigateToWGs, handleNavigateToDossiers, onRefreshBlogDatagrid]);
817
+ /**
818
+ * Il risultato è davvero a video: le pagine restano montate anche in secondo piano, e senza questo
819
+ * bacheca e anteprima scaricherebbero il documento fuori campo.
820
+ */
821
+ const isSearchResultOnScreen = isVisible && !isOpenDcmtForm && !isOpenDetails && !isOpenMaster;
822
+ const tmBlog = useMemo(() => _jsx(TMDcmtBlog, { tid: focusedItem?.TID, did: focusedItem?.DID, isPageVisible: isSearchResultOnScreen, fetchBlogDataTrigger: refreshBlogTrigger, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), [focusedItem, allTasks, refreshBlogTrigger, isSearchResultOnScreen, handleNavigateToWGs, handleNavigateToDossiers, onRefreshBlogDatagrid]);
709
823
  const tmSysMetadata = useMemo(() => _jsx(TMMetadataValues, { layoutMode: LayoutModes.Update, openChooserBySingleClick: true, TID: focusedItem?.TID, isReadOnly: true, deviceType: deviceType, metadataValues: currentMetadataValues.filter(o => (o.mid != undefined && o.mid <= 100)), metadataValuesOrig: currentMetadataValues.filter(o => (o.mid != undefined && o.mid <= 100)), validationItems: [] }), [focusedItem, currentMetadataValues, deviceType]);
710
- const tmDcmtPreview = useMemo(() => _jsx(TMDcmtPreviewWrapper, { refreshPreviewTrigger: refreshPreviewTrigger, currentDcmt: currentDcmt, onBack: getOnBackHandler() }), [currentDcmt, refreshPreviewTrigger]);
824
+ const tmDcmtPreview = useMemo(() => _jsx(TMDcmtPreviewWrapper, { refreshPreviewTrigger: refreshPreviewTrigger, currentDcmt: currentDcmt, isPageVisible: isSearchResultOnScreen, onBack: backHandlerSecondary }), [currentDcmt, refreshPreviewTrigger, isSearchResultOnScreen, backHandlerSecondary]);
711
825
  // Auto-fetch indexing info when drawer is open and focusedItem changes
712
826
  useEffect(() => {
713
827
  if (!focusedItem || !showIndexingInfo)
@@ -762,8 +876,24 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
762
876
  if (!ftExplanation) {
763
877
  return (_jsxs(StyledPlaceholder, { children: [" ", _jsx("p", { children: "Nessuna info disponibile per questo documento" }), " "] }));
764
878
  }
765
- return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden', width: '100%' }, children: [_jsx("div", { style: { padding: '10px', overflow: 'auto', flex: 1 }, children: _jsx("div", { dangerouslySetInnerHTML: { __html: ftExplanation } }) }), _jsxs(StyledIndexingInfoSection, { children: [_jsxs(StyledIndexingToggle, { onClick: handleToggleIndexingInfo, disabled: loadingIndexingInfo, children: [_jsx(StyledLeftContent, { children: _jsx("span", { children: SDKUI_Localizator.IndexingInformation }) }), _jsx(StyledRightContent, { children: _jsx(StyledChevron, { "$isOpen": showIndexingInfo, children: "\u25BC" }) })] }), showIndexingInfo && indexingInfo && (_jsxs(StyledIndexingInfoBox, { children: [_jsx("div", { dangerouslySetInnerHTML: { __html: indexingInfo } }), loadingIndexingInfo && (_jsxs("div", { style: { position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', background: 'rgba(255, 255, 255, 0.9)', padding: '10px', borderRadius: '4px', boxShadow: '0 2px 8px rgba(0,0,0,0.15)' }, children: [SDKUI_Localizator.Loading, "..."] }))] }))] })] }));
879
+ return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden', width: '100%' }, children: [_jsx("div", { style: { padding: '10px', overflow: 'auto', flex: 1 }, children: _jsx("div", { dangerouslySetInnerHTML: { __html: ftExplanation } }) }), _jsxs(StyledIndexingInfoSection, { children: [_jsxs(StyledIndexingToggle, { onClick: handleToggleIndexingInfo, disabled: loadingIndexingInfo, children: [_jsx(StyledLeftContent, { children: _jsx("span", { children: SDKUI_Localizator.IndexingInformation }) }), _jsx(StyledRightContent, { children: _jsx(StyledChevron, { $isOpen: showIndexingInfo, children: "\u25BC" }) })] }), showIndexingInfo && indexingInfo && (_jsxs(StyledIndexingInfoBox, { children: [_jsx("div", { dangerouslySetInnerHTML: { __html: indexingInfo } }), loadingIndexingInfo && (_jsxs("div", { style: { position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', background: 'rgba(255, 255, 255, 0.9)', padding: '10px', borderRadius: '4px', boxShadow: '0 2px 8px rgba(0,0,0,0.15)' }, children: [SDKUI_Localizator.Loading, "..."] }))] }))] })] }));
766
880
  }, [selectedSearchResult, focusedItem, indexingInfo, showIndexingInfo, loadingIndexingInfo]);
881
+ /**
882
+ * Su mobile i pannelli si mostrano uno per volta, quindi il layout non va ricordato; con groupId
883
+ * i pannelli sono di un panel manager esterno, che ha un layout suo. Senza la barra laterale
884
+ * l'utente non può aprire/chiudere i pannelli: non ha senso applicargli il layout salvato (li
885
+ * troverebbe aperti senza poterli chiudere) né lasciargli sporcare quello condiviso.
886
+ * Il layout salvato vale solo per il login con Surfer: gli altri moduli hanno layout propri.
887
+ */
888
+ const isLayoutPersisted = SDK_Globals.tmSession?.SessionDescr?.appModuleID === AppModules.SURFER && !isMobile && !groupId?.length && showSearchResultSidebar && PERSISTED_LAYOUT_CONTEXTS.includes(context);
889
+ /**
890
+ * Pannelli che questo risultato non può mostrare (la bacheca è l'unico, vedi PanelDisabledStateHandler).
891
+ * Il layout è condiviso con gli altri risultati aperti: qui non vanno aperti quando il layout lo chiede,
892
+ * e il loro stato salvato non va toccato, altrimenti li si chiuderebbe dove invece sono attivi.
893
+ */
894
+ const disabledLayoutPanelIds = isBoardDisabled ? ['tmBlog'] : [];
895
+ /** Bacheca aperta nel layout salvato: da riaprire quando il tipo documento torna a prevederla */
896
+ const savedBlogVisible = isLayoutPersisted && (getSearchResultPanelLayout()['tmBlog']?.visible ?? false);
767
897
  const allInitialPanelVisibility = {
768
898
  'tmSearchResult': true,
769
899
  'tmBlog': false,
@@ -786,9 +916,11 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
786
916
  component: tmSearchResult,
787
917
  panelContainer: {
788
918
  title: getTitleHeader(),
919
+ enableTitleMarquee: true,
789
920
  showHeader: showToolbarHeader,
790
921
  allowMaximize: !isMobile,
791
- onBack: getOnBackHandler(true),
922
+ onBack: backHandler,
923
+ backCaption: backCaption,
792
924
  onClose: isClosable ? onBack : undefined,
793
925
  toolbar: searchResutlToolbar
794
926
  },
@@ -803,7 +935,7 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
803
935
  panelContainer: {
804
936
  title: SDKUI_Localizator.BlogCase,
805
937
  allowMaximize: !isMobile,
806
- onBack: getOnBackHandler(),
938
+ onBack: backHandlerSecondary,
807
939
  }
808
940
  },
809
941
  toolbarOptions: { icon: _jsx(IconBoard, { fontSize: 24 }), visible: getSearchToolbarVisibility(SDK_Globals.tmSession?.SessionDescr?.appModuleID ?? AppModules.SURFER).tmBlog, orderNumber: 2, isActive: allInitialPanelVisibility['tmBlog'] }
@@ -816,7 +948,7 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
816
948
  panelContainer: {
817
949
  title: SDKUI_Localizator.MetadataSystem,
818
950
  allowMaximize: !isMobile,
819
- onBack: getOnBackHandler(),
951
+ onBack: backHandlerSecondary,
820
952
  }
821
953
  },
822
954
  toolbarOptions: { icon: _jsx(IconDcmtTypeSys, { fontSize: 24 }), visible: getSearchToolbarVisibility(SDK_Globals.tmSession?.SessionDescr?.appModuleID ?? AppModules.SURFER).tmSysMetadata, orderNumber: 3, isActive: allInitialPanelVisibility['tmSysMetadata'] }
@@ -830,7 +962,7 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
830
962
  panelContainer: {
831
963
  title: SDKUI_Localizator.ResultDetails,
832
964
  allowMaximize: !isMobile,
833
- onBack: getOnBackHandler(),
965
+ onBack: backHandlerSecondary,
834
966
  }
835
967
  },
836
968
  toolbarOptions: { icon: _jsx(IconPlatform, { fontSize: 20 }), visible: getSearchToolbarVisibility(SDK_Globals.tmSession?.SessionDescr?.appModuleID ?? AppModules.SURFER).tmFullTextSearch, orderNumber: 4, isActive: allInitialPanelVisibility['tmFullTextSearch'] }
@@ -844,21 +976,49 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
844
976
  },
845
977
  toolbarOptions: { icon: _jsx(IconShow, { fontSize: 24 }), visible: getSearchToolbarVisibility(SDK_Globals.tmSession?.SessionDescr?.appModuleID ?? AppModules.SURFER).tmDcmtPreview, orderNumber: context === SearchResultContext.FREE_SEARCH ? 5 : 4, isActive: allInitialPanelVisibility['tmDcmtPreview'] }
846
978
  }
847
- ], [tmSearchResult, tmBlog, tmSysMetadata, tmDcmtPreview, tmFullTextSearch, showToolbarHeader, context, isMobile]);
848
- return (_jsxs(StyledMultiViewPanel, { "$isVisible": isVisible, children: [_jsx(StyledMultiViewPanel, { "$isVisible": !isOpenDcmtForm && !isOpenDetails && !isOpenMaster, style: {
979
+ ], [tmSearchResult, tmBlog, tmSysMetadata, tmDcmtPreview, tmFullTextSearch, showToolbarHeader, context, isMobile, backHandler, backHandlerSecondary, isClosable, onBack, backCaption]);
980
+ /** Contenuto del panel manager: con groupId sta nel provider del contenitore, altrimenti in quello qui sotto */
981
+ const panelManagerContent = (_jsxs(_Fragment, { children: [_jsx(PanelDisabledStateHandler, { isBoardDisabled: isBoardDisabled, savedBlogVisible: savedBlogVisible }), isLayoutPersisted && _jsx(SavedLayoutSyncHandler, { disabledPanelIds: disabledLayoutPanelIds }), _jsx(ShowMainPanelBridge, { showMainPanelRef: showMainPanelRef }), _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", parentId: groupId, showToolbar: showSearchResultSidebar })] }));
982
+ return (_jsxs(StyledMultiViewPanel, { $isVisible: isVisible, children: [_jsx(StyledMultiViewPanel, { $isVisible: (!isOpenDcmtForm || isDcmtFormModal) && !isOpenDetails && !isOpenMaster, style: {
849
983
  display: 'flex',
850
984
  flexDirection: isMobile ? 'column' : 'row',
851
985
  justifyContent: 'space-between',
852
986
  gap: Gutters.getGutters(),
853
987
  width: '100%',
854
988
  height: '100%',
855
- }, children: _jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showWaitPanel, showWaitPanelPrimary: showPrimary, showWaitPanelSecondary: showSecondary, waitPanelTitle: waitPanelTitle, waitPanelTextPrimary: waitPanelTextPrimary, waitPanelValuePrimary: waitPanelValuePrimary, waitPanelMaxValuePrimary: waitPanelMaxValuePrimary, waitPanelTextSecondary: waitPanelTextSecondary, waitPanelValueSecondary: waitPanelValueSecondary, waitPanelMaxValueSecondary: waitPanelMaxValueSecondary, isCancelable: true, abortController: abortController, children: _jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showCicoWaitPanel, showWaitPanelPrimary: showCicoPrimaryProgress, waitPanelTitle: cicoWaitPanelTitle, waitPanelTextPrimary: cicoPrimaryProgressText, waitPanelValuePrimary: cicoPrimaryProgressValue, waitPanelMaxValuePrimary: cicoPrimaryProgressMax, isCancelable: true, abortController: abortControllerLocal, children: (groupId && groupId.length > 0) ?
856
- _jsxs(_Fragment, { children: [_jsx(PanelDisabledStateHandler, { isBoardDisabled: isBoardDisabled }), _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", parentId: groupId, showToolbar: showSearchResultSidebar })] })
857
- :
858
- _jsxs(TMPanelManagerProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: initialPanelDimensions, initialDimensions: initialPanelDimensions, initialMobilePanelId: 'tmSearchResult', children: [_jsx(PanelDisabledStateHandler, { isBoardDisabled: isBoardDisabled }), _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", parentId: groupId, showToolbar: showSearchResultSidebar })] }) }) }) }), renderDcmtOperations] }));
989
+ }, children: _jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showWaitPanel, showWaitPanelPrimary: showPrimary, showWaitPanelSecondary: showSecondary, waitPanelTitle: waitPanelTitle, waitPanelTextPrimary: waitPanelTextPrimary, waitPanelValuePrimary: waitPanelValuePrimary, waitPanelMaxValuePrimary: waitPanelMaxValuePrimary, waitPanelTextSecondary: waitPanelTextSecondary, waitPanelValueSecondary: waitPanelValueSecondary, waitPanelMaxValueSecondary: waitPanelMaxValueSecondary, isCancelable: true, abortController: abortController, children: _jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showCicoWaitPanel, showWaitPanelPrimary: showCicoPrimaryProgress, waitPanelTitle: cicoWaitPanelTitle, waitPanelTextPrimary: cicoPrimaryProgressText, waitPanelValuePrimary: cicoPrimaryProgressValue, waitPanelMaxValuePrimary: cicoPrimaryProgressMax, isCancelable: true, abortController: abortControllerLocal, children: (groupId && groupId.length > 0) ? panelManagerContent
990
+ // Senza le prop di persistenza il provider si comporta come quello base:
991
+ // i contesti che non ricordano il layout restano come prima
992
+ : _jsx(TMPanelManagerWithPersistenceProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: initialPanelDimensions, initialDimensions: initialPanelDimensions, initialMobilePanelId: 'tmSearchResult', isPersistenceEnabled: isLayoutPersisted && hasSearchResultPanelLayout(), persistPanelStates: isLayoutPersisted ? (state) => saveSearchResultPanelLayout(state, disabledLayoutPanelIds) : undefined, persistedPanelStates: isLayoutPersisted ? getSearchResultPanelLayout() : undefined, children: panelManagerContent }) }) }) }), renderDcmtOperations] }));
859
993
  };
860
994
  export default TMSearchResult;
861
- const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, inputFocusedItem, allowMultipleSelection = true, showExportForm = false, onFocusedItemChanged, onDownloadDcmtsAsync, onVisibleItemChanged, inputSelectedItems = [], lastUpdateSearchTime, searchResult, onSelectionChanged, onDblClick, showSearchTMDatagrid, updateDataColumnsFromDataGrid, updateDataSourceFromDataGrid, updateSelectedRowKeysFromDataGrid, disableAutoFocus = false, dcmtsReturned, dcmtsFound }) => {
995
+ /** Cerca una voce di operazione per id, anche dentro i sottomenu */
996
+ const findOperationItemById = (items, id) => {
997
+ for (const item of items) {
998
+ if (item.id === id)
999
+ return item;
1000
+ const found = item.submenu ? findOperationItemById(item.submenu, id) : undefined;
1001
+ if (found)
1002
+ return found;
1003
+ }
1004
+ return undefined;
1005
+ };
1006
+ /**
1007
+ * Azioni della colonna di riga. Gli id sono quelli di useDocumentOperations, così il comportamento è
1008
+ * lo stesso del menu contestuale; icone e colori sono allineati alle altre griglie mentre il tooltip
1009
+ * resta il nome dell'operazione. "Cancella" è la cancellazione logica: ripristino ed eliminazione
1010
+ * fisica restano nel menu contestuale, dove la scelta è esplicita.
1011
+ */
1012
+ const rowActions = [
1013
+ { operationId: 'open-form', icon: _jsx(IconEdit, { fontSize: 18, color: TMColors.primary }) },
1014
+ { operationId: 'dup', icon: _jsx(IconDuplicate, { fontSize: 18, color: TMColors.tertiary }) },
1015
+ { operationId: 'del-log', icon: _jsx(IconDelete, { fontSize: 18, color: TMColors.error }), isVisible: (rowData) => rowData?.ISLOGDEL != 1 },
1016
+ ];
1017
+ const rowActionsStyles = {
1018
+ cell: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '14px' },
1019
+ icon: { cursor: 'pointer', display: 'flex' },
1020
+ };
1021
+ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, inputFocusedItem, allowMultipleSelection = true, showExportForm = false, onFocusedItemChanged, onDownloadDcmtsAsync, onVisibleItemChanged, inputSelectedItems = [], lastUpdateSearchTime, searchResult, onSelectionChanged, onDblClick, showSearchTMDatagrid, updateDataColumnsFromDataGrid, updateDataSourceFromDataGrid, updateSelectedRowKeysFromDataGrid, disableAutoFocus = false, dcmtsReturned, dcmtsFound, showCounterConfig = true, counterConfig, showActionsColumn = false, compactPager = false, onRowActionRequest, }) => {
862
1022
  const [dataSource, setDataSource] = useState();
863
1023
  const [columns, setColumns] = useState([]);
864
1024
  const [selectedRowKeys, setSelectedRowKeys] = useState([]);
@@ -879,8 +1039,8 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
879
1039
  useEffect(() => {
880
1040
  updateDataSourceFromDataGrid(dataSource ?? []);
881
1041
  }, [dataSource]);
882
- const { loadDataListsAsync, renderDataListCell, dataListsCache } = useDataListItem();
883
- const { loadUsersAsync, renderUserIdViewer, usersCache } = useDataUserIdItem();
1042
+ const { loadDataListsAsync, renderDataListCell, dataListsCache, getDataListItem } = useDataListItem();
1043
+ const { loadUsersAsync, renderUserIdViewer, usersCache, getUserItem, getCompleteUserName } = useDataUserIdItem();
884
1044
  useEffect(() => {
885
1045
  // Sincronizza focusedItem con inputFocusedItem dal padre
886
1046
  if (deepCompare(inputFocusedItem, focusedItem))
@@ -1112,6 +1272,57 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
1112
1272
  });
1113
1273
  return cols;
1114
1274
  }, [searchResult, dataType, cellRender, getDisplayFormat, dataListsCache, usersCache]);
1275
+ /**
1276
+ * Colonne in cui il testo mostrato è diverso dal valore archiviato: date e numeri formattati, descrizioni
1277
+ * di liste dati e utenti. Su queste la ricerca della griglia va fatta sul testo mostrato, altrimenti non
1278
+ * trova nulla (es. cercando 29/01/2023 su una data, che nei dati è una stringa ISO).
1279
+ * Le cache sono ref lette al momento della ricerca: a quel punto sono già popolate.
1280
+ */
1281
+ const searchTextGetters = useMemo(() => {
1282
+ const getters = new Map();
1283
+ const columnsOfResult = searchResult?.dtdResult?.columns;
1284
+ if (!columnsOfResult)
1285
+ return getters;
1286
+ const uniqueKeys = generateUniqueColumnKeys(columnsOfResult, searchResult?.fromTID);
1287
+ columnsOfResult.forEach((col, index) => {
1288
+ const dataField = uniqueKeys[index];
1289
+ if (!dataField)
1290
+ return;
1291
+ const dataDomain = MetadataDataDomains[(col.extendedProperties?.["DataDomain"] ?? "None")];
1292
+ const dataListID = Number(col.extendedProperties?.["DataListID"]);
1293
+ if (dataDomain === MetadataDataDomains.DataList && dataListID) {
1294
+ getters.set(dataField, (rowData) => getDataListItem(dataListID, rowData?.[dataField])?.name ?? String(rowData?.[dataField] ?? ''));
1295
+ return;
1296
+ }
1297
+ if (dataDomain === MetadataDataDomains.UserID) {
1298
+ getters.set(dataField, (rowData) => {
1299
+ const rawValue = rowData?.[dataField];
1300
+ // Un campo utente vuoto non mostra nulla: senza questo controllo Number('') darebbe 0, cioè l'utente di sistema
1301
+ if (rawValue === undefined || rawValue === null || rawValue === '')
1302
+ return '';
1303
+ const userId = Number(rawValue);
1304
+ if (Number.isNaN(userId))
1305
+ return String(rawValue);
1306
+ if (userId === 0)
1307
+ return SDKUI_Localizator.SystemUser ?? '';
1308
+ const ud = getUserItem(userId);
1309
+ return (ud ? getCompleteUserName(ud.domain, ud.name) : undefined) ?? String(rawValue);
1310
+ });
1311
+ return;
1312
+ }
1313
+ // Data e numero vengono mostrati con il formato definito sulle proprietà estese della colonna
1314
+ const { format, formatCulture } = getColumnFormatInfo(col);
1315
+ if (col.dataType === DataColumnTypes.DateTime) {
1316
+ getters.set(dataField, (rowData) => getDateDisplayText(rowData?.[dataField], format, formatCulture));
1317
+ return;
1318
+ }
1319
+ if (col.dataType === DataColumnTypes.Number) {
1320
+ getters.set(dataField, (rowData) => getNumberDisplayText(rowData?.[dataField], format, formatCulture));
1321
+ }
1322
+ });
1323
+ return getters;
1324
+ }, [searchResult, getDataListItem, getUserItem, getCompleteUserName]);
1325
+ const customizeColumns = useMemo(() => customizeSearchByDisplayText(searchTextGetters), [searchTextGetters]);
1115
1326
  /**
1116
1327
  * Effect che carica i dati necessari e genera le colonne della griglia.
1117
1328
  * Esegue il caricamento delle cache (DataList e UserID) in parallelo prima di generare le colonne,
@@ -1181,6 +1392,14 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
1181
1392
  let newDataSource = searchResultDescriptorToSimpleArray(searchResult);
1182
1393
  setDataSource(newDataSource);
1183
1394
  }, [lastUpdateSearchTime]);
1395
+ const gridSorting = useMemo(() => ({ mode: 'multiple' }), []);
1396
+ const gridSelection = useMemo(() => ({ mode: allowMultipleSelection ? 'multiple' : 'single' }), [allowMultipleSelection]);
1397
+ const useNativeScrollbar = SDKUI_Globals.userSettings?.themeSettings.gridSettings.useNativeScrollbar === 1;
1398
+ const gridScrolling = useMemo(() => ({
1399
+ columnRenderingMode: 'virtual',
1400
+ rowRenderingMode: 'standard',
1401
+ useNative: useNativeScrollbar
1402
+ }), [useNativeScrollbar]);
1184
1403
  // Handles selection change in the data grid
1185
1404
  const handleSelectionChange = useCallback((e) => {
1186
1405
  if (onSelectionChanged === undefined)
@@ -1203,6 +1422,9 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
1203
1422
  // Era sull'icona, non fare nulla
1204
1423
  return;
1205
1424
  }
1425
+ // Due click rapidi su un'icona della colonna azioni non devono aprire anche il form
1426
+ if (e.event?.target.closest('.tm-row-actions'))
1427
+ return;
1206
1428
  // Verifica che il documento abbia TID e DID validi prima di procedere
1207
1429
  if (!e.data.TID || !e.data.DID) {
1208
1430
  ShowAlert({
@@ -1216,8 +1438,43 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
1216
1438
  onFocusedItemChanged?.(e.data);
1217
1439
  onDblClick();
1218
1440
  }, [onDblClick]);
1441
+ /**
1442
+ * Colonna delle azioni di riga, in testa alla griglia (subito dopo la checkbox di selezione, che
1443
+ * DevExtreme tiene sempre per prima). Vive solo qui e non nello stato `columns`, che è quello
1444
+ * sincronizzato col padre per l'esportazione: una colonna senza dataField finirebbe in Excel come
1445
+ * colonna vuota.
1446
+ *
1447
+ * Le operazioni sono lette da una ref perché `operationItems` è ricostruito a ogni render del
1448
+ * padre: usarlo come dipendenza renderebbe nuova la colonna, e con essa `dataColumns`, ad ogni
1449
+ * giro. La cellRender le rilegge a ogni ridisegno della griglia, quindi resta comunque aggiornata.
1450
+ */
1451
+ const operationItemsRef = useRef(operationItems);
1452
+ operationItemsRef.current = operationItems;
1453
+ const actionsColumn = useMemo(() => ({
1454
+ caption: '',
1455
+ width: 110,
1456
+ alignment: 'center',
1457
+ allowSorting: false,
1458
+ allowFiltering: false,
1459
+ allowHeaderFiltering: false,
1460
+ allowResizing: false,
1461
+ allowReordering: false,
1462
+ allowHiding: false,
1463
+ allowExporting: false,
1464
+ showInColumnChooser: false,
1465
+ cssClass: 'tm-row-actions',
1466
+ cellRender: (cellData) => (_jsx("div", { style: rowActionsStyles.cell, children: rowActions.map(action => {
1467
+ const operation = findOperationItemById(operationItemsRef.current, action.operationId);
1468
+ if (!operation || operation.visible === false)
1469
+ return null;
1470
+ if (action.isVisible && !action.isVisible(cellData.data))
1471
+ return null;
1472
+ return (_jsx("span", { style: rowActionsStyles.icon, title: operation.name, onClick: () => onRowActionRequest?.(action.operationId, cellData.data), children: action.icon }, action.operationId));
1473
+ }) })),
1474
+ }), [onRowActionRequest]);
1219
1475
  const dataColumns = useMemo(() => {
1220
1476
  return [
1477
+ ...(showActionsColumn ? [actionsColumn] : []),
1221
1478
  {
1222
1479
  dataType: "object",
1223
1480
  dataField: 'FILEEXT',
@@ -1231,7 +1488,7 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
1231
1488
  },
1232
1489
  ...columns.filter(col => col.dataField !== 'FILEEXT')
1233
1490
  ];
1234
- }, [columns, onDownloadDcmtsAsync, openInOffice]);
1491
+ }, [columns, onDownloadDcmtsAsync, openInOffice, showActionsColumn, actionsColumn]);
1235
1492
  const onContentReady = useCallback((e) => {
1236
1493
  if (e === undefined)
1237
1494
  return;
@@ -1242,21 +1499,22 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
1242
1499
  setVisibleItems(visibleData);
1243
1500
  }, []);
1244
1501
  useEffect(() => { onVisibleItemChanged?.(visibleItems); }, [visibleItems]);
1245
- return _jsxs("div", { style: { width: "100%", height: "100%" }, children: [!isDataGridReady && (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', width: '100%', gap: '10px' }, children: [_jsx(LoadIndicator, { height: 60, width: 60 }), _jsx("div", { children: SDKUI_Localizator.Loading })] })), isDataGridReady && _jsx(TMDataGrid, { ref: dataGridRef, id: "tm-search-result", keyExpr: "rowIndex", dataColumns: dataColumns, dataSource: dataSource, repaintChangesOnly: true, selectedRowKeys: selectedRowKeys, focusedRowKey: disableAutoFocus ? undefined : Number(focusedItem?.rowIndex ?? 0), showSearchPanel: showSearchTMDatagrid, showFilterPanel: true, sorting: { mode: "multiple" }, selection: { mode: allowMultipleSelection ? 'multiple' : 'single' }, pageSize: pageSize, onSelectionChanged: handleSelectionChange, onFocusedRowChanged: handleFocusedRowChange, onRowDblClick: onRowDblClick, onContentReady: onContentReady, showHeaderColumnChooser: true, onKeyDown: onKeyDown, customContextMenuItems: operationItems, counterConfig: {
1502
+ const defaultCounterItems = dcmtsReturned !== undefined && dcmtsFound !== undefined
1503
+ ? new Map([
1504
+ [CounterItemKey.allItems, {
1505
+ key: CounterItemKey.allItems,
1246
1506
  show: true,
1247
- items: dcmtsReturned !== undefined && dcmtsFound !== undefined
1248
- ? new Map([
1249
- [CounterItemKey.allItems, {
1250
- key: CounterItemKey.allItems,
1251
- show: true,
1252
- caption: `${dcmtsReturned} restituiti su ${dcmtsFound} trovati`,
1253
- value: `${dcmtsReturned}/${dcmtsFound}`,
1254
- icon: _jsx(IconAll, {}),
1255
- order: -1
1256
- }]
1257
- ])
1258
- : undefined
1259
- } })] });
1507
+ caption: `${dcmtsReturned} restituiti su ${dcmtsFound} trovati`,
1508
+ value: `${dcmtsReturned}/${dcmtsFound}`,
1509
+ icon: _jsx(IconAll, {}),
1510
+ order: -1
1511
+ }]
1512
+ ])
1513
+ : undefined;
1514
+ const gridCounterConfig = showCounterConfig
1515
+ ? { ...counterConfig, show: true, items: counterConfig?.items ?? defaultCounterItems }
1516
+ : { show: false };
1517
+ return _jsxs("div", { style: { width: "100%", height: "100%" }, children: [!isDataGridReady && (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', width: '100%', gap: '10px' }, children: [_jsx(LoadIndicator, { height: 60, width: 60 }), _jsx("div", { children: SDKUI_Localizator.Loading })] })), isDataGridReady && _jsx(TMDataGrid, { ref: dataGridRef, id: "tm-search-result", keyExpr: "rowIndex", dataColumns: dataColumns, dataSource: dataSource, customizeColumns: customizeColumns, repaintChangesOnly: true, selectedRowKeys: selectedRowKeys, focusedRowKey: disableAutoFocus ? undefined : Number(focusedItem?.rowIndex ?? 0), showSearchPanel: showSearchTMDatagrid, showFilterPanel: true, sorting: gridSorting, selection: gridSelection, scrolling: gridScrolling, pageSize: pageSize, compactPager: compactPager, onSelectionChanged: handleSelectionChange, onFocusedRowChanged: handleFocusedRowChange, onRowDblClick: onRowDblClick, onContentReady: onContentReady, showHeaderColumnChooser: true, onKeyDown: onKeyDown, customContextMenuItems: operationItems, counterConfig: gridCounterConfig })] });
1260
1518
  };
1261
1519
  //#region TMSearchResultSelector
1262
1520
  const StyledItemTemplate = styled.div `
@@ -1317,14 +1575,29 @@ const TMSearchResultSelector = ({ searchResults = [], disableAccordionIfSingleCa
1317
1575
  }
1318
1576
  }
1319
1577
  }, [sortedCategories.length, autoSelectFirst]);
1578
+ // La preselezione esterna va applicata una volta per valore: riapplicarla a ogni cambio di
1579
+ // searchResults faceva sì che un refresh annullasse la navigazione dell'utente.
1580
+ const appliedSelectedTIDRef = useRef(undefined);
1320
1581
  useEffect(() => {
1321
- if (selectedTID !== undefined) {
1322
- const found = searchResults.find(r => Number(r.fromTID) === selectedTID);
1323
- handleSelect(found);
1582
+ // Richiesta ritirata: dimentichiamo il valore applicato, così se il chiamante richiede di
1583
+ // nuovo lo stesso TID la preselezione riparte
1584
+ if (selectedTID === undefined) {
1585
+ appliedSelectedTIDRef.current = undefined;
1586
+ return;
1324
1587
  }
1588
+ if (appliedSelectedTIDRef.current === selectedTID)
1589
+ return;
1590
+ const found = searchResults.find(r => Number(r.fromTID) === selectedTID);
1591
+ if (!found)
1592
+ return; // risultati non ancora arrivati: riproviamo al prossimo giro
1593
+ appliedSelectedTIDRef.current = selectedTID;
1594
+ handleSelect(found);
1325
1595
  }, [selectedTID, searchResults]);
1326
- const handleSelect = useCallback((result) => {
1327
- if (selectedResult !== result && result !== undefined) {
1596
+ // force = true per i click dell'utente: la selezione va notificata anche se il tipo documento è già quello selezionato
1597
+ const handleSelect = useCallback((result, force = false) => {
1598
+ if (result === undefined)
1599
+ return;
1600
+ if (selectedResult !== result || force) {
1328
1601
  setSelectedResult(result);
1329
1602
  onSelectionChanged?.(result);
1330
1603
  }
@@ -1369,32 +1642,88 @@ const TMSearchResultSelector = ({ searchResults = [], disableAccordionIfSingleCa
1369
1642
  renderItem: (result, isSelected) => (_jsxs("div", { style: { width: '100%', padding: '5px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [_jsx(TMTidViewer, { tid: result.fromTID, did: Number(result.dtdResult?.rows?.[0]?.[1]), showIcon: true }), _jsx("div", { style: { padding: 3, display: 'flex', alignItems: 'center', justifyContent: 'center', backgroundColor: 'white', color: 'gray', borderRadius: 3 }, children: result.dcmtsReturned })] })),
1370
1643
  itemHeight: 40
1371
1644
  })), [sortedCategories, groupedResults, searchResults]);
1372
- const renderCategoryItems = (category) => (_jsx("div", { style: { padding: '5px', height: '100%', overflow: 'auto' }, children: groupedResults[category].map((result, index) => (_jsx(MemoizedStyledItemTemplate, { "$isSelected": selectedResult === result, onClick: () => handleSelect(result), children: renderItemTemplate(result) }, index))) }));
1645
+ const renderCategoryItems = (category) => (_jsx("div", { style: { padding: '5px', height: '100%', overflow: 'auto' }, children: groupedResults[category].map((result, index) => (_jsx(MemoizedStyledItemTemplate, { $isSelected: selectedResult === result, onClick: () => handleSelect(result, true), children: renderItemTemplate(result) }, index))) }));
1373
1646
  if (disableAccordionIfSingleCategory && sortedCategories.length === 1) {
1374
1647
  const category = sortedCategories[0];
1375
1648
  return renderCategoryItems(category);
1376
1649
  }
1377
- return (_jsx(TMAccordionNew, { groups: accordionGroups, selectedItem: selectedResult, onSelectedItemChange: (result) => handleSelect(result) }));
1650
+ return (_jsx(TMAccordionNew, { groups: accordionGroups, selectedItem: selectedResult, onSelectedItemChange: (result) => handleSelect(result, true) }));
1378
1651
  };
1379
1652
  //#endregion TMSearchResultSelector
1380
- const PanelDisabledStateHandler = ({ isBoardDisabled }) => {
1381
- const { setPanelVisibilityById, setToolbarButtonDisabled } = useTMPanelManagerContext();
1653
+ /** Senza UI: vive dentro il provider e passa a onBack, via ref, l'azione "mostra il pannello lista". */
1654
+ const ShowMainPanelBridge = ({ showMainPanelRef }) => {
1655
+ const { setPanelVisibilityById } = useTMPanelManagerContext();
1382
1656
  useEffect(() => {
1383
- if (isBoardDisabled) {
1384
- setToolbarButtonDisabled('tmBlog', true);
1385
- setPanelVisibilityById('tmBlog', false);
1386
- }
1387
- else {
1388
- setToolbarButtonDisabled('tmBlog', false);
1389
- }
1657
+ // Su mobile mostrare un pannello nasconde gli altri; su desktop la lista è già visibile
1658
+ showMainPanelRef.current = () => setPanelVisibilityById('tmSearchResult', true);
1659
+ return () => { showMainPanelRef.current = null; };
1660
+ }, [setPanelVisibilityById, showMainPanelRef]);
1661
+ return null;
1662
+ };
1663
+ /** Senza UI: allinea i pannelli quando il layout viene salvato da un altro risultato di ricerca già aperto */
1664
+ const SavedLayoutSyncHandler = ({ disabledPanelIds }) => {
1665
+ const { panelVisibility, panelDimensions, maximizedPanels, isResizingActive, setPanelVisibilityById, setPanelDimensionsById } = useTMPanelManagerContext();
1666
+ // Il layout è condiviso fra i risultati aperti: si sottoscrive la firma, che è una stringa, perché
1667
+ // React confronta le letture per riferimento e su un oggetto ri-renderizzerebbe all'infinito
1668
+ const savedLayoutSignature = useSyncExternalStore(subscribeSearchResultPanelLayout, getSearchResultPanelLayoutSignature);
1669
+ useEffect(() => {
1670
+ // Con un pannello massimizzato o un separatore in movimento comanda l'utente di questa istanza
1671
+ if (maximizedPanels.length > 0 || isResizingActive)
1672
+ return;
1673
+ // Al mount panelVisibility è ancora vuota: lo stato iniziale lo applica il provider.
1674
+ // Un pannello disabilitato qui non va aperto, gli altri si allineano comunque
1675
+ const panelsToApply = Object.entries(getSearchResultPanelLayout())
1676
+ .filter(([id, state]) => panelVisibility[id] !== undefined && !(state?.visible && disabledPanelIds.includes(id)));
1677
+ panelsToApply.forEach(([id, state]) => {
1678
+ const isVisible = state?.visible ?? false;
1679
+ if (panelVisibility[id] !== isVisible)
1680
+ setPanelVisibilityById(id, isVisible);
1681
+ });
1682
+ // Le larghezze salvate valgono come pesi, non come percentuali: qui si normalizzano sui soli pannelli
1683
+ // che questo risultato apre davvero, così lo spazio di quelli scartati non resta vuoto
1684
+ const panelsToShow = panelsToApply.filter(([, state]) => state?.visible && parseFloat(state.width) > 0 && parseFloat(state.height) > 0);
1685
+ const weightTotal = panelsToShow.reduce((total, [, state]) => total + parseFloat(state.width), 0);
1686
+ if (weightTotal <= 0)
1687
+ return;
1688
+ // Dopo la visibilità, che accoda un suo ricalcolo delle quote: così restano quelle salvate.
1689
+ // Le quote sono arrotondate, altrimenti due risultati si rincorrono sugli ultimi decimali
1690
+ panelsToShow.forEach(([id, state]) => {
1691
+ const width = `${Math.round(parseFloat(state.width) / weightTotal * 10000) / 100}%`;
1692
+ if (panelDimensions[id]?.width === width && panelDimensions[id]?.height === state.height)
1693
+ return;
1694
+ setPanelDimensionsById(id, width, state.height);
1695
+ });
1696
+ }, [savedLayoutSignature]);
1697
+ return null;
1698
+ };
1699
+ const PanelDisabledStateHandler = ({ isBoardDisabled, savedBlogVisible = false }) => {
1700
+ const { panelVisibility, setPanelVisibilityById, setToolbarButtonDisabled } = useTMPanelManagerContext();
1701
+ const isBlogVisible = panelVisibility['tmBlog'] ?? false;
1702
+ useEffect(() => {
1703
+ setToolbarButtonDisabled('tmBlog', isBoardDisabled);
1390
1704
  }, [isBoardDisabled]);
1705
+ /**
1706
+ * Senza bacheca nel tipo documento il pannello va chiuso ogni volta che ricompare, non solo al cambio
1707
+ * di stato: il layout salvato viene applicato dopo questo effetto e può riportarlo a video.
1708
+ * È un effetto di layout per chiuderlo prima che venga disegnato, altrimenti lampeggia.
1709
+ */
1710
+ useLayoutEffect(() => {
1711
+ if (isBoardDisabled && isBlogVisible)
1712
+ setPanelVisibilityById('tmBlog', false);
1713
+ }, [isBoardDisabled, isBlogVisible]);
1714
+ // Bacheca di nuovo prevista: si riapre come da layout salvato. isBlogVisible non è fra le dipendenze,
1715
+ // altrimenti riaprirebbe il pannello appena chiuso dall'utente
1716
+ useEffect(() => {
1717
+ if (!isBoardDisabled && savedBlogVisible && !isBlogVisible)
1718
+ setPanelVisibilityById('tmBlog', true);
1719
+ }, [isBoardDisabled, savedBlogVisible]);
1391
1720
  return null;
1392
1721
  };
1393
- const TMDcmtPreviewWrapper = ({ refreshPreviewTrigger, currentDcmt, isVisible, onBack }) => {
1722
+ const TMDcmtPreviewWrapper = ({ refreshPreviewTrigger, currentDcmt, isVisible, isPageVisible = true, onBack }) => {
1394
1723
  const { setPanelVisibilityById, toggleMaximize, isResizingActive, countVisibleLeafPanels } = useTMPanelManagerContext();
1395
1724
  const deviceType = useDeviceType();
1396
1725
  const isMobile = deviceType === DeviceType.MOBILE;
1397
- return (_jsx(TMDcmtPreview, { dcmtData: currentDcmt, onClosePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('tmDcmtPreview', false) : undefined, onBack: onBack, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => toggleMaximize("tmDcmtPreview") : undefined, isResizingActive: isResizingActive, isVisible: isVisible }, refreshPreviewTrigger));
1726
+ return (_jsx(TMDcmtPreview, { dcmtData: currentDcmt, onClosePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('tmDcmtPreview', false) : undefined, onBack: onBack, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => toggleMaximize("tmDcmtPreview") : undefined, isResizingActive: isResizingActive, isVisible: isVisible && isPageVisible }, refreshPreviewTrigger));
1398
1727
  };
1399
1728
  // Styled Components
1400
1729
  const StyledPlaceholder = styled.div `