@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
@@ -132,6 +132,19 @@ export interface TMRelationViewerProps {
132
132
  * Useful to disable interactions (like context menu) during loading.
133
133
  */
134
134
  onLoadingStateChanged?: (isLoading: boolean) => void;
135
+ /**
136
+ * Invoked on mount to hand over a function that stops the ongoing correlations
137
+ * calculation: no further GetMetadata calls are performed and only the
138
+ * correlations already calculated are kept.
139
+ * The function is synchronous, so it can be safely called right before
140
+ * unmounting the viewer (e.g. when navigating back).
141
+ */
142
+ onStopCalculationReady?: (stopCalculation: () => void) => void;
143
+ /**
144
+ * Callback invoked when the calculation has actually been stopped
145
+ * (loadData terminated after an abort request).
146
+ */
147
+ onCalculationStopped?: () => void;
135
148
  }
136
149
  /**
137
150
  * Check if document type has detail relations
@@ -150,7 +163,7 @@ export declare const getDisplayValueByColumn: (col: DataColumnDescriptor | undef
150
163
  * For each document, fetches complete metadata using GetMetadataAsync to ensure
151
164
  * all metadata properties (isSpecialSearchOutput, permissions, etc.) are available
152
165
  */
153
- export declare const searchResultToDataSource: (searchResult: SearchResultDescriptor | undefined, hideSysMetadata?: boolean) => Promise<any[]>;
166
+ export declare const searchResultToDataSource: (searchResult: SearchResultDescriptor | undefined, hideSysMetadata?: boolean, signal?: AbortSignal) => Promise<any[]>;
154
167
  export declare const DEFAULT_RELATION_EXPAND_LEVEL = 4;
155
168
  declare const TMRelationViewer: React.FC<TMRelationViewerProps>;
156
169
  export default TMRelationViewer;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
3
- import { DcmtTypeListCacheService, SDK_Globals, DataColumnTypes, MetadataFormats, MetadataDataDomains, RelationCacheService, RelationTypes, UserListCacheService, LayoutModes } from "@topconsultnpm/sdk-ts";
4
- import { genUniqueId, IconFolder, IconBackhandIndexPointingRight, IconCircleInfo, getDcmtCicoStatus, IconChevronDown, IconChevronRight, SDKUI_Localizator, buildDcmtDisplayName, SDKUI_Globals, searchResultToMetadataValues } from '../../../helper';
3
+ import { DcmtTypeListCacheService, SDK_Globals, DataColumnTypes, MetadataDataDomains, RelationCacheService, RelationTypes, UserListCacheService, LayoutModes } from "@topconsultnpm/sdk-ts";
4
+ import { genUniqueId, IconFolder, IconBackhandIndexPointingRight, IconCircleInfo, getDcmtCicoStatus, IconChevronDown, IconChevronRight, SDKUI_Localizator, buildDcmtDisplayName, SDKUI_Globals, searchResultToMetadataValues, getColumnFormatInfo, formatDateTimeByMetadataFormat, formatNumberByMetadataFormat } from '../../../helper';
5
5
  import ShowAlert from '../../base/TMAlert';
6
6
  import TMToppyMessage from '../../../helper/TMToppyMessage';
7
7
  import { TMColors } from '../../../utils/theme';
@@ -55,35 +55,14 @@ export const getDisplayValueByColumn = (col, value) => {
55
55
  return value;
56
56
  if (col.dataType === DataColumnTypes.Text)
57
57
  return value;
58
- const format = MetadataFormats[(col.extendedProperties?.["Format"] ?? "None")];
59
- const formatCulture = col.extendedProperties?.["FormatCulture"] ?? window.navigator.language;
60
- if (col.dataType === DataColumnTypes.DateTime) {
61
- const date = new Date(value);
62
- switch (format) {
63
- case MetadataFormats.ShortDate: return date.toLocaleString(formatCulture, formatCulture == "it-IT" ? { year: "numeric", month: "2-digit", day: "2-digit" } : { dateStyle: 'short' });
64
- case MetadataFormats.ShortTime: return date.toLocaleString(formatCulture, { timeStyle: 'short' });
65
- case MetadataFormats.ShortDateLongTime: return date.toLocaleString(formatCulture, formatCulture == "it-IT" ? { year: "numeric", month: "2-digit", day: "2-digit", hour: '2-digit', minute: '2-digit', second: '2-digit' } : { dateStyle: 'short', timeStyle: 'medium' }).replace(',', '');
66
- case MetadataFormats.ShortDateShortTime: return date.toLocaleString(formatCulture, formatCulture == "it-IT" ? { year: "numeric", month: "2-digit", day: "2-digit", hour: '2-digit', minute: '2-digit' } : { dateStyle: 'short', timeStyle: 'short' }).replace(',', '');
67
- case MetadataFormats.LongDate: return date.toLocaleString(formatCulture, { weekday: "long", year: "numeric", month: "long", day: "numeric" });
68
- case MetadataFormats.LongTime: return date.toLocaleString(formatCulture, { timeStyle: 'medium' });
69
- case MetadataFormats.LongDateLongTime: return date.toLocaleString(formatCulture, { weekday: "long", year: "numeric", month: "long", day: "numeric", hour: '2-digit', minute: '2-digit', second: '2-digit' });
70
- case MetadataFormats.LongDateShortTime: return date.toLocaleString(formatCulture, { weekday: "long", year: "numeric", month: "long", day: "numeric", hour: '2-digit', minute: '2-digit' });
71
- default: return date.toLocaleString(formatCulture, { dateStyle: 'short' });
72
- }
73
- }
74
- if (col.dataType === DataColumnTypes.Number) {
75
- return value.toLocaleString(formatCulture, { useGrouping: format == MetadataFormats.NumberWithThousandsSeparator });
76
- }
77
- if (format == MetadataFormats.None)
78
- return value;
79
- if (format == MetadataFormats.CurrencyEuro)
80
- return value.toLocaleString(formatCulture, { style: 'currency', currency: "EUR" });
81
- if (format == MetadataFormats.CurrencyDollar)
82
- return value.toLocaleString(formatCulture, { style: 'currency', currency: "USD" });
83
- if (format == MetadataFormats.CurrencyPound)
84
- return value.toLocaleString(formatCulture, { style: 'currency', currency: "GBP" });
85
- if (format == MetadataFormats.CurrencyYen)
86
- return value.toLocaleString(formatCulture, { style: 'currency', currency: "JPY" });
58
+ // Formato e cultura di visualizzazione definiti sulle proprietà estese della colonna
59
+ const { format, formatCulture } = getColumnFormatInfo(col);
60
+ // Date: il valore arriva come stringa e va prima convertito in Date
61
+ if (col.dataType === DataColumnTypes.DateTime)
62
+ return formatDateTimeByMetadataFormat(new Date(value), format, formatCulture);
63
+ // Numeri (incluse valute): stessa formattazione usata da TMSearchResult
64
+ if (col.dataType === DataColumnTypes.Number)
65
+ return formatNumberByMetadataFormat(value, format, formatCulture);
87
66
  return value;
88
67
  };
89
68
  /**
@@ -91,7 +70,7 @@ export const getDisplayValueByColumn = (col, value) => {
91
70
  * For each document, fetches complete metadata using GetMetadataAsync to ensure
92
71
  * all metadata properties (isSpecialSearchOutput, permissions, etc.) are available
93
72
  */
94
- export const searchResultToDataSource = async (searchResult, hideSysMetadata) => {
73
+ export const searchResultToDataSource = async (searchResult, hideSysMetadata, signal) => {
95
74
  const rows = searchResult?.dtdResult?.rows ?? [];
96
75
  const output = [];
97
76
  // Find TID and DID column indices
@@ -99,6 +78,9 @@ export const searchResultToDataSource = async (searchResult, hideSysMetadata) =>
99
78
  const tidColIndex = columns.findIndex(col => col.caption?.toUpperCase() === 'TID');
100
79
  const didColIndex = columns.findIndex(col => col.caption?.toUpperCase() === 'DID');
101
80
  for (let index = 0; index < rows.length; index++) {
81
+ // Interruzione richiesta dall'utente: restituisce i documenti già elaborati
82
+ if (signal?.aborted)
83
+ break;
102
84
  const row = rows[index];
103
85
  // Extract TID and DID from row
104
86
  const tid = tidColIndex >= 0 ? Number(row[tidColIndex]) : searchResult?.fromTID;
@@ -123,9 +105,11 @@ export const searchResultToDataSource = async (searchResult, hideSysMetadata) =>
123
105
  ? (mvd.md?.name ?? '').toUpperCase()
124
106
  : (mvd.md?.name ?? '');
125
107
  if (key) {
108
+ // Find the corresponding column by MID to format the value
109
+ const column = dtdResult?.columns?.find(c => Number(c.extendedProperties?.["MID"] ?? "0") === mvd.mid);
126
110
  item[key] = {
127
111
  md: mvd.md,
128
- value: mvd.value
112
+ value: getDisplayValueByColumn(column, mvd.value)
129
113
  };
130
114
  }
131
115
  }
@@ -163,7 +147,7 @@ export const searchResultToDataSource = async (searchResult, hideSysMetadata) =>
163
147
  return output;
164
148
  };
165
149
  export const DEFAULT_RELATION_EXPAND_LEVEL = 4; // Default maximum depth level for expansion (can be adjusted)
166
- const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndicator = true, allowShowZeroDcmts = true, initialShowZeroDcmts = false, allowedTIDs, allowMultipleSelection = false, focusedItem, selectedItems, onFocusedItemChanged, onSelectedItemsChanged, onAllItemsChanged, onDocumentDoubleClick, customItemRender, customDocumentStyle, customMainContainerContent, customDocumentContent, showMetadataNames = false, maxDepthLevel = 2, invertMasterNavigation = true, additionalStaticItems, showMainDocument = true, labelMainContainer, onNoRelationsFound, onItemContextMenu, focusedItemFormData = [], showExpandAllButton = false, defaultExpandAll = false, onLoadingStateChanged }) => {
150
+ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndicator = true, allowShowZeroDcmts = true, initialShowZeroDcmts = false, allowedTIDs, allowMultipleSelection = false, focusedItem, selectedItems, onFocusedItemChanged, onSelectedItemsChanged, onAllItemsChanged, onDocumentDoubleClick, customItemRender, customDocumentStyle, customMainContainerContent, customDocumentContent, showMetadataNames = false, maxDepthLevel = 2, invertMasterNavigation = true, additionalStaticItems, showMainDocument = true, labelMainContainer, onNoRelationsFound, onItemContextMenu, focusedItemFormData = [], showExpandAllButton = false, defaultExpandAll = false, onLoadingStateChanged, onStopCalculationReady, onCalculationStopped }) => {
167
151
  // State
168
152
  const [dcmtTypes, setDcmtTypes] = useState([]);
169
153
  const [treeData, setTreeData] = useState([]);
@@ -178,6 +162,8 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
178
162
  const [waitPanelValuePrimary, setWaitPanelValuePrimary] = useState(0);
179
163
  const [waitPanelMaxValuePrimary, setWaitPanelMaxValuePrimary] = useState(0);
180
164
  const [abortController] = useState(new AbortController());
165
+ // True quando l'utente ha interrotto il calcolo delle correlazioni (pulsante "Interrompi")
166
+ const [loadStoppedByUser, setLoadStoppedByUser] = useState(false);
181
167
  const [showExpansionWaitPanel, setShowExpansionWaitPanel] = useState(false);
182
168
  const [expansionWaitPanelText, setExpansionWaitPanelText] = useState('');
183
169
  const [expansionWaitPanelValue, setExpansionWaitPanelValue] = useState(0);
@@ -210,6 +196,27 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
210
196
  const isLoading = showWaitPanel || showExpansionWaitPanel;
211
197
  onLoadingStateChanged?.(isLoading);
212
198
  }, [showWaitPanel, showExpansionWaitPanel, onLoadingStateChanged]);
199
+ // Mantiene l'AbortController dell'espansione in corso accessibile da callback stabili
200
+ const expansionAbortControllerRef = React.useRef(undefined);
201
+ useEffect(() => {
202
+ expansionAbortControllerRef.current = expansionAbortController;
203
+ }, [expansionAbortController]);
204
+ /**
205
+ * Interrompe il calcolo delle correlazioni (iniziale e/o espansione in corso):
206
+ * non vengono eseguite ulteriori chiamate GetMetadata e vengono mantenute
207
+ * solo le correlazioni già calcolate.
208
+ * È sincrona: può essere invocata immediatamente prima di smontare il viewer
209
+ * (es. pulsante "Indietro"), quando un effect non farebbe in tempo.
210
+ */
211
+ const stopCalculation = useCallback(() => {
212
+ if (!abortController.signal.aborted)
213
+ abortController.abort();
214
+ expansionAbortControllerRef.current?.abort();
215
+ }, [abortController]);
216
+ // Espone la funzione di interruzione al componente padre
217
+ useEffect(() => {
218
+ onStopCalculationReady?.(stopCalculation);
219
+ }, [onStopCalculationReady, stopCalculation]);
213
220
  // Sincronizza expandLevel quando userSettings.searchSettings.relationExpandLevel cambia
214
221
  useEffect(() => {
215
222
  const globalExpandLevel = SDKUI_Globals.userSettings?.searchSettings?.relationExpandLevel;
@@ -239,7 +246,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
239
246
  /**
240
247
  * Recursively retrieve detail documents (adapted from TMMasterDetailDcmts.tsx)
241
248
  */
242
- const getDetailDcmtsAsync = useCallback(async (mTID, mDID, maxLevel) => {
249
+ const getDetailDcmtsAsync = useCallback(async (mTID, mDID, maxLevel, signal) => {
243
250
  const items = [];
244
251
  if (!mTID)
245
252
  return [];
@@ -259,6 +266,9 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
259
266
  return items;
260
267
  const results = await searchEngine.GetAllDetailDcmtsAsync(mTID, mDID) ?? [];
261
268
  for (const searchResult of results) {
269
+ // Interruzione richiesta dall'utente: restituisce le correlazioni già calcolate
270
+ if (signal?.aborted)
271
+ break;
262
272
  // Skip if allowedTIDs is set and this TID is not allowed
263
273
  if (allowedTIDs && searchResult.fromTID && !allowedTIDs.includes(searchResult.fromTID)) {
264
274
  continue;
@@ -280,7 +290,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
280
290
  expanded: false,
281
291
  hidden: false
282
292
  };
283
- const source = await searchResultToDataSource(searchResult);
293
+ const source = await searchResultToDataSource(searchResult, undefined, signal);
284
294
  if (source && source.length > 0) {
285
295
  const dcmtDetails = [];
286
296
  // Check once if this document type can have detail relations
@@ -326,7 +336,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
326
336
  /**
327
337
  * Recursively retrieve master documents
328
338
  */
329
- const getMasterDcmtsAsync = useCallback(async (dTID, dDID, maxLevel) => {
339
+ const getMasterDcmtsAsync = useCallback(async (dTID, dDID, maxLevel, signal) => {
330
340
  const items = [];
331
341
  if (!dTID)
332
342
  return [];
@@ -346,6 +356,9 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
346
356
  return items;
347
357
  const results = await searchEngine.GetAllMasterDcmtsAsync(dTID, dDID) ?? [];
348
358
  for (const searchResult of results) {
359
+ // Interruzione richiesta dall'utente: restituisce le correlazioni già calcolate
360
+ if (signal?.aborted)
361
+ break;
349
362
  // Skip if allowedTIDs is set and this TID is not allowed
350
363
  if (allowedTIDs && searchResult.fromTID && !allowedTIDs.includes(searchResult.fromTID)) {
351
364
  continue;
@@ -367,7 +380,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
367
380
  expanded: false,
368
381
  hidden: false
369
382
  };
370
- const source = await searchResultToDataSource(searchResult);
383
+ const source = await searchResultToDataSource(searchResult, undefined, signal);
371
384
  if (source && source.length > 0) {
372
385
  const dcmtMasters = [];
373
386
  // Check once if this document type can have master relations (for inverted mode)
@@ -595,7 +608,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
595
608
  }
596
609
  const dtd = await DcmtTypeListCacheService.GetAsync(dcmt.TID);
597
610
  // Parse document values
598
- const docValues = await searchResultToDataSource(result);
611
+ const docValues = await searchResultToDataSource(result, undefined, abortController.signal);
599
612
  const docRow = docValues.length > 0 ? docValues[0] : undefined;
600
613
  // Generate unique GUID for this container
601
614
  const containerGUID = genUniqueId();
@@ -604,16 +617,21 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
604
617
  // ========================================================================
605
618
  if (isForMaster && !invertMasterNavigation) {
606
619
  // Carica i master documents
607
- const masterDocs = await getMasterDcmtsAsync(dcmt.TID, dcmt.DID, maxDepthLevel);
620
+ const masterDocs = await getMasterDcmtsAsync(dcmt.TID, dcmt.DID, maxDepthLevel, abortController.signal);
608
621
  // Per ogni master, carica i suoi detail (incluso il documento corrente)
609
622
  for (const masterContainer of masterDocs) {
623
+ if (abortController.signal.aborted)
624
+ break;
610
625
  if (!masterContainer.items)
611
626
  continue;
612
627
  // Per ogni master document nel container, carica i detail
613
628
  for (const masterDoc of masterContainer.items) {
629
+ // Interruzione richiesta dall'utente: mantiene i dati già calcolati
630
+ if (abortController.signal.aborted)
631
+ break;
614
632
  if (masterDoc.tid && masterDoc.did) {
615
633
  // Carica i detail del master (incluso il documento di partenza)
616
- const detailDocs = await getDetailDcmtsAsync(masterDoc.tid, masterDoc.did, 1);
634
+ const detailDocs = await getDetailDcmtsAsync(masterDoc.tid, masterDoc.did, 1, abortController.signal);
617
635
  masterDoc.items = detailDocs;
618
636
  masterDoc.itemsCount = detailDocs.length;
619
637
  masterDoc.isLoaded = true;
@@ -646,8 +664,8 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
646
664
  else {
647
665
  // Load related documents (detail or master based on isForMaster flag)
648
666
  const relatedDocs = isForMaster
649
- ? await getMasterDcmtsAsync(dcmt.TID, dcmt.DID, maxDepthLevel)
650
- : await getDetailDcmtsAsync(dcmt.TID, dcmt.DID, maxDepthLevel);
667
+ ? await getMasterDcmtsAsync(dcmt.TID, dcmt.DID, maxDepthLevel, abortController.signal)
668
+ : await getDetailDcmtsAsync(dcmt.TID, dcmt.DID, maxDepthLevel, abortController.signal);
651
669
  // Se showMainDocument è false, mostra i container dei dettagli direttamente sotto il container principale
652
670
  if (!showMainDocument) {
653
671
  // Check if a container for this TID already exists in the tree
@@ -794,8 +812,15 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
794
812
  // Check recursively if there are any actual documents
795
813
  return hasNoActualDocuments(container.items);
796
814
  });
815
+ // Calcolo interrotto dall'utente: mostra solo ciò che è stato calcolato,
816
+ // senza notificare l'assenza di correlazioni (il risultato è parziale, non definitivo)
817
+ const wasStopped = abortController.signal.aborted;
818
+ if (wasStopped) {
819
+ setLoadStoppedByUser(true);
820
+ onCalculationStopped?.();
821
+ }
797
822
  // If no relations found, notify parent
798
- if (hasNoRelations && onNoRelationsFound) {
823
+ if (!wasStopped && hasNoRelations && onNoRelationsFound) {
799
824
  onNoRelationsFound();
800
825
  }
801
826
  // Update metadata error count state
@@ -823,7 +848,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
823
848
  // Now it will correctly detect expanded nodes and add infoMessage if all children are hidden
824
849
  const processedTree = updateHiddenProperty(expandedTree);
825
850
  setTreeData(processedTree);
826
- }, [inputDcmts, dcmtTypes, maxDepthLevel, isForMaster, invertMasterNavigation, getDetailDcmtsAsync, getMasterDcmtsAsync, abortController, updateHiddenProperty, showMainDocument, labelMainContainer, onNoRelationsFound]);
851
+ }, [inputDcmts, dcmtTypes, maxDepthLevel, isForMaster, invertMasterNavigation, getDetailDcmtsAsync, getMasterDcmtsAsync, abortController, updateHiddenProperty, showMainDocument, labelMainContainer, onNoRelationsFound, onCalculationStopped]);
827
852
  /**
828
853
  * Merge main tree data with additional static items
829
854
  */
@@ -1066,15 +1091,15 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
1066
1091
  let loadedItems = [];
1067
1092
  if (isForMaster && !invertMasterNavigation) {
1068
1093
  // Original mode: detail documents load detail documents (natural detail→detail navigation)
1069
- loadedItems = await getDetailDcmtsAsync(node.tid, node.did, 1);
1094
+ loadedItems = await getDetailDcmtsAsync(node.tid, node.did, 1, newAbortController.signal);
1070
1095
  }
1071
1096
  else if (isForMaster) {
1072
1097
  // Inverted master mode: load master documents
1073
- loadedItems = await getMasterDcmtsAsync(node.tid, node.did, 1);
1098
+ loadedItems = await getMasterDcmtsAsync(node.tid, node.did, 1, newAbortController.signal);
1074
1099
  }
1075
1100
  else {
1076
1101
  // Standard mode: load detail documents
1077
- loadedItems = await getDetailDcmtsAsync(node.tid, node.did, 1);
1102
+ loadedItems = await getDetailDcmtsAsync(node.tid, node.did, 1, newAbortController.signal);
1078
1103
  }
1079
1104
  // Espandi automaticamente il primo container se ci sono documenti correlati
1080
1105
  if (loadedItems.length > 0 && loadedItems[0].isContainer) {
@@ -1436,13 +1461,13 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
1436
1461
  let loadedItems = [];
1437
1462
  // Carica i documenti correlati (detail o master in base alla modalità)
1438
1463
  if (isForMaster && !invertMasterNavigation) {
1439
- loadedItems = await getDetailDcmtsAsync(node.tid, node.did, 1);
1464
+ loadedItems = await getDetailDcmtsAsync(node.tid, node.did, 1, newAbortController.signal);
1440
1465
  }
1441
1466
  else if (isForMaster) {
1442
- loadedItems = await getMasterDcmtsAsync(node.tid, node.did, 1);
1467
+ loadedItems = await getMasterDcmtsAsync(node.tid, node.did, 1, newAbortController.signal);
1443
1468
  }
1444
1469
  else {
1445
- loadedItems = await getDetailDcmtsAsync(node.tid, node.did, 1);
1470
+ loadedItems = await getDetailDcmtsAsync(node.tid, node.did, 1, newAbortController.signal);
1446
1471
  }
1447
1472
  // Applica le regole di visibilità (showZeroDcmts)
1448
1473
  expandedNode.items = updateHiddenProperty(loadedItems);
@@ -1543,6 +1568,10 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
1543
1568
  return _jsx("div", { style: { padding: '20px', textAlign: 'center' }, children: _jsx(TMWaitPanel, { title: SDKUI_Localizator.LoadingDetailDocuments, showPrimary: true, textPrimary: waitPanelTextPrimary, valuePrimary: waitPanelValuePrimary, maxValuePrimary: waitPanelMaxValuePrimary, isCancelable: true, abortController: abortController, onAbortClick: () => { setTimeout(() => { abortController.abort(); }, 1000); } }) });
1544
1569
  }
1545
1570
  if (mergedTreeData.length === 0) {
1571
+ // Calcolo interrotto dall'utente prima di aver calcolato qualsiasi correlazione
1572
+ if (loadStoppedByUser) {
1573
+ return _jsx(TMToppyMessage, { message: SDKUI_Localizator.RelationsCalculationStopped });
1574
+ }
1546
1575
  // Se NON isForMaster e tutti i GetMetadataAsync sono falliti
1547
1576
  if (!isForMaster && metadataErrorCount === inputDcmts.length) {
1548
1577
  return _jsx(TMToppyMessage, { message: SDKUI_Localizator.DocumentsNotAvailableOrNoCorrelations });
@@ -1553,7 +1582,8 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
1553
1582
  return _jsx("div", { style: { padding: '20px', textAlign: 'center', color: '#666' }, children: SDKUI_Localizator.NoRelationsAvailable });
1554
1583
  }
1555
1584
  // Se isForMaster e non ci sono master documents disponibili
1556
- if (isForMaster && totalMasterDocuments === 0) {
1585
+ // (se il calcolo è stato interrotto l'albero parziale viene comunque mostrato)
1586
+ if (isForMaster && totalMasterDocuments === 0 && !loadStoppedByUser) {
1557
1587
  return _jsx(TMToppyMessage, { message: SDKUI_Localizator.NoMasterDocumentsAvailable });
1558
1588
  }
1559
1589
  return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0, width: '100%' }, children: [showExpandAllButton && (_jsxs("div", { style: { flexShrink: 0, display: 'flex', alignItems: 'center', gap: '6px', height: '40px', paddingLeft: '10px', backgroundColor: TMColors.toolbar_background }, children: [_jsx(TMTooltip, { content: expandLevel === 0
@@ -5,13 +5,13 @@ import TMSavedQuerySelector from './TMSavedQuerySelector';
5
5
  import TMTreeSelector from './TMTreeSelector';
6
6
  import { TabPanel, Item } from 'devextreme-react/tab-panel';
7
7
  import TMSearchQueryPanel, { refreshLastSearch } from './TMSearchQueryPanel';
8
- import { getSysAllDcmtsSQD, IconFilter, IconRecentlyViewed, IconSavedQuery, IconTree, removeMruTid, SDKUI_Globals, SDKUI_Localizator, updateMruTids } from '../../../helper';
8
+ import { getSysAllDcmtsSQD, SYS_ALL_DCMTS_SQD_ID, IconFilter, IconRecentlyViewed, IconSavedQuery, IconTree, mergeSearchResultsAppend, removeMruTid, SDKUI_Globals, SDKUI_Localizator, updateMruTids } from '../../../helper';
9
9
  import TMSearchResult from './TMSearchResult';
10
10
  import TMRecentsManager from '../../grids/TMRecentsManager';
11
11
  import { SearchResultContext } from '../../../ts';
12
12
  import { useDeviceType, DeviceType } from '../../base/TMDeviceProvider';
13
13
  import { StyledMultiViewPanel } from '../../base/Styled';
14
- import { useTMPanelManagerContext } from '../../layout/panelManager/TMPanelManagerContext';
14
+ import { TMPanelManagerProvider, useTMPanelManagerContext } from '../../layout/panelManager/TMPanelManagerContext';
15
15
  import TMPanelManagerContainer from '../../layout/panelManager/TMPanelManagerContainer';
16
16
  import { TMPanelManagerWithPersistenceProvider } from '../../layout/panelManager/TMPanelManagerWithPersistenceProvider';
17
17
  import { TMExceptionBoxManager } from '../../base/TMPopUp';
@@ -32,7 +32,7 @@ const TMSearch = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTask
32
32
  const [currentSearchView, setCurrentSearchView] = useState(TMSearchViews.Search);
33
33
  const [currentSQDMode, setCurrentSQDMode] = useState(1);
34
34
  const [lastQdSearched, setLastQdSearched] = useState();
35
- const [showSearchResults, setShowSearchResults] = useState(true);
35
+ const [showSearchResults, setShowSearchResults] = useState(!onlyShowSearchQueryPanel);
36
36
  const [maxDcmtsToBeReturned, setMaxDcmtsToBeReturned] = useState(SDKUI_Globals.userSettings.searchSettings?.maxDcmtsToBeReturned ?? 1000);
37
37
  const deviceType = useDeviceType();
38
38
  useEffect(() => {
@@ -152,6 +152,42 @@ const TMSearch = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTask
152
152
  if (sqdToBeSet)
153
153
  await setSqdAsync?.(sqdToBeSet);
154
154
  }, []);
155
+ // --- REFRESH DEI PANNELLI ---
156
+ // Scorciatoie: rilegge dal server l'elenco dei tipi documento, così le scorciatoie riflettono
157
+ // quelli aggiunti o rimossi. La nuova identità di mruTIDs fa ricaricare i descrittori a TMRecentsManager.
158
+ const refreshRecentsAsync = useCallback(async () => {
159
+ DcmtTypeListCacheService.RemoveAllWithoutMetadata();
160
+ await DcmtTypeListCacheService.GetAllWithoutMetadataAsync();
161
+ setMruTIDs([...SDKUI_Globals.userSettings.searchSettings.mruTIDs]);
162
+ }, []);
163
+ // Ricerche rapide: invalida la cache delle saved query e ricarica l'elenco del tipo documento corrente
164
+ const refreshSavedQueriesAsync = useCallback(async () => {
165
+ // loadDataSQDsAsync riporta la selezione sulla prima tab: il refresh non deve spostare quella scelta dall'utente
166
+ const sqdMode = currentSQDMode;
167
+ await loadDataSQDsAsync(true, fromDTD?.id ?? currentTID);
168
+ setCurrentSQDMode(sqdMode);
169
+ }, [fromDTD?.id, currentTID, currentSQDMode]);
170
+ // Pannello dei metadati: rilegge dal server i metadati del tipo documento e la definizione della
171
+ // ricerca rapida corrente, con cui il pannello ricostruisce i filtri (i valori digitati vengono persi)
172
+ const refreshSearchQueryPanelAsync = useCallback(async () => {
173
+ const tid = fromDTD?.id ?? currentTID;
174
+ if (!tid)
175
+ return;
176
+ const dtd = await DcmtTypeListCacheService.GetAsync(tid, true, undefined, false, true);
177
+ setFromDTD(dtd);
178
+ // Passare da undefined forza la ricostruzione dei filtri anche quando la query selezionata non cambia
179
+ const sqdToRestore = currentSQD;
180
+ SavedQueryCacheService.Remove();
181
+ await setSQDAsync(undefined);
182
+ // La ricerca di sistema non è in cache: va ricostruita, così recepisce i metadati appena riletti
183
+ await setSQDAsync(sqdToRestore?.id === SYS_ALL_DCMTS_SQD_ID ? await getSysAllDcmtsSQD(tid, false) : sqdToRestore);
184
+ // mruTIDs è tra le dipendenze perché setSQDAsync lo legge
185
+ }, [fromDTD?.id, currentTID, currentSQD, mruTIDs]);
186
+ // Prima di ogni ricerca il pannello rilegge i metadati del tipo documento: si recepisce il descrittore
187
+ // aggiornato, così anche il resto della vista (titoli, badge, form dei metadati) lavora sulla lista corrente
188
+ const handleDcmtTypeReloaded = useCallback((dtd) => {
189
+ setFromDTD(dtd);
190
+ }, []);
155
191
  const onRefreshSearchAsyncDatagrid = async () => {
156
192
  try {
157
193
  if (lastQdSearched) {
@@ -164,6 +200,32 @@ const TMSearch = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTask
164
200
  console.error("Error refreshing search:", error);
165
201
  }
166
202
  };
203
+ const handleSearchCompleted = useCallback((searchResult, qd, append) => {
204
+ if (searchResult.length <= 0) {
205
+ // In ricerca normale un array vuoto resetta i risultati; in accoda si mantiene il set accumulato
206
+ if (!append)
207
+ setSearchResult(searchResult);
208
+ return;
209
+ }
210
+ const newResult = searchResult[0];
211
+ // In modalità accoda unisce il nuovo risultato a quello precedente (più recenti in cima).
212
+ setSearchResult(prev => {
213
+ if (append && prev.length > 0 && prev[0]?.fromTID === newResult?.fromTID) {
214
+ const merged = mergeSearchResultsAppend(prev[0], newResult);
215
+ return merged ? [merged] : searchResult;
216
+ }
217
+ return searchResult;
218
+ });
219
+ setLastQdSearched(qd);
220
+ setCurrentSearchView(TMSearchViews.Result);
221
+ // Salvataggio ultimi 10 TIDs
222
+ let fromTID = searchResult?.[0].fromTID;
223
+ let newMruTIDS = updateMruTids(SDKUI_Globals.userSettings.searchSettings.mruTIDs, fromTID);
224
+ SDKUI_Globals.userSettings.searchSettings.mruTIDs = newMruTIDS;
225
+ setMruTIDs(newMruTIDS);
226
+ setCurrentMruTID(fromTID);
227
+ setShowSearchResults(true);
228
+ }, []);
167
229
  const isMobile = deviceType === DeviceType.MOBILE;
168
230
  const isTabletOrMobile = deviceType === DeviceType.TABLET || deviceType === DeviceType.MOBILE;
169
231
  // --- JSX WRAPPERS ---
@@ -182,23 +244,11 @@ const TMSearch = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTask
182
244
  SDKUI_Globals.userSettings.searchSettings.mruTIDs = newMruTIDS;
183
245
  setMruTIDs(newMruTIDS);
184
246
  } }), [mruTIDs, currentMruTID, deviceType]);
185
- const tmSearchQueryPanelElement = useMemo(() => _jsx(TMSearchQueryPanelWrapper, { passToArchiveCallback: passToArchiveCallback, isExpertMode: isExpertMode, showBackToResultButton: searchResult.length > 0, fromDTD: fromDTD, SQD: currentSQD, inputMids: inputMids, maxDcmtsToBeReturned: maxDcmtsToBeReturned, onBackToResult: () => { setCurrentSearchView(TMSearchViews.Result); }, onSearchCompleted: (searchResult, qd) => {
186
- setSearchResult(searchResult);
187
- if (searchResult.length <= 0)
188
- return;
189
- setLastQdSearched(qd);
190
- setCurrentSearchView(TMSearchViews.Result);
191
- // Salvataggio ultimi 10 TIDs
192
- let fromTID = searchResult?.[0].fromTID;
193
- let newMruTIDS = updateMruTids(SDKUI_Globals.userSettings.searchSettings.mruTIDs, fromTID);
194
- SDKUI_Globals.userSettings.searchSettings.mruTIDs = newMruTIDS;
195
- setMruTIDs(newMruTIDS);
196
- setCurrentMruTID(fromTID);
197
- setShowSearchResults(true);
198
- }, onSqdSaved: async (newSqd) => {
247
+ const tmSearchQueryPanelElement = useMemo(() => _jsx(TMSearchQueryPanelWrapper, { isSearchViewOnScreen: currentSearchView === TMSearchViews.Search, passToArchiveCallback: passToArchiveCallback, isExpertMode: isExpertMode, showBackToResultButton: searchResult.length > 0, fromDTD: fromDTD, SQD: currentSQD, inputMids: inputMids, maxDcmtsToBeReturned: maxDcmtsToBeReturned, onBackToResult: () => { if (onlyShowSearchQueryPanel)
248
+ setShowSearchResults(true); setCurrentSearchView(TMSearchViews.Result); }, onSearchCompleted: handleSearchCompleted, onRefreshRequested: refreshSearchQueryPanelAsync, onDcmtTypeReloaded: handleDcmtTypeReloaded, onSqdSaved: async (newSqd) => {
199
249
  await loadDataSQDsAsync(true, newSqd.masterTID);
200
250
  await setSQDAsync(newSqd);
201
- } }), [fromDTD, showSearchResults, setShowSearchResults, currentSQD, isExpertMode, mruTIDs, searchResult, passToArchiveCallback, inputMids, maxDcmtsToBeReturned]);
251
+ } }), [fromDTD, showSearchResults, setShowSearchResults, currentSQD, currentSearchView, isExpertMode, mruTIDs, searchResult, passToArchiveCallback, inputMids, maxDcmtsToBeReturned, handleSearchCompleted, refreshSearchQueryPanelAsync, handleDcmtTypeReloaded, onlyShowSearchQueryPanel]);
202
252
  const tmSavedQuerySelectorElement = useMemo(() => _jsxs(TabPanel, { width: "100%", height: "100%", showNavButtons: true, repaintChangesOnly: true, selectedIndex: currentSQDMode, onSelectedIndexChange: (index) => setCurrentSQDMode(index), children: [(currentTID || currentSQD) ? _jsx(Item, { title: fromDTD?.nameLoc, children: _jsx(TMSavedQuerySelectorWrapper, { allowShowSearch: false, items: filteredByTIDSQDs, selectedId: currentSQD?.id, onRefreshData: () => { loadDataSQDsAsync(true); }, onItemClick: (sqd) => {
203
253
  onSQDItemClick(sqd, setSQDAsync);
204
254
  }, onDeleted: (sqd) => onSQDDeleted(sqd, sqd.id == currentSQD?.id ? filteredByTIDSQDs.find(o => o.id == 1) : currentSQD, setSQDAsync), refreshFavoriteSavedQueries: refreshFavoriteSavedQueries }) }) : _jsx(_Fragment, {}), _jsx(Item, { title: SDKUI_Localizator.AllFemale, children: _jsx(TMSavedQuerySelectorWrapper, { allowShowSearch: true, items: allSQDs, manageDefault: false, onItemClick: (sqd) => {
@@ -250,7 +300,14 @@ const TMSearch = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTask
250
300
  {
251
301
  id: 'TMRecentsManager',
252
302
  name: SDKUI_Localizator.Shortcuts,
253
- contentOptions: { component: tmRecentsManagerElement, panelContainer: { title: SDKUI_Localizator.Shortcuts, totalItems: mruTIDs.length } },
303
+ contentOptions: {
304
+ component: tmRecentsManagerElement,
305
+ panelContainer: {
306
+ title: SDKUI_Localizator.Shortcuts,
307
+ totalItems: mruTIDs.length,
308
+ onRefresh: refreshRecentsAsync
309
+ }
310
+ },
254
311
  toolbarOptions: { icon: _jsx(IconRecentlyViewed, { fontSize: 24 }), visible: true, orderNumber: 2, isActive: allInitialPanelVisibility['TMRecentsManager'] }
255
312
  },
256
313
  {
@@ -262,11 +319,33 @@ const TMSearch = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTask
262
319
  {
263
320
  id: 'TMSavedQuerySelector',
264
321
  name: SDK_Localizator.SavedQueries,
265
- contentOptions: { component: tmSavedQuerySelectorElement, panelContainer: { title: SDK_Localizator.SavedQueries } },
322
+ contentOptions: {
323
+ component: tmSavedQuerySelectorElement,
324
+ panelContainer: {
325
+ title: SDK_Localizator.SavedQueries,
326
+ onRefresh: refreshSavedQueriesAsync
327
+ }
328
+ },
266
329
  toolbarOptions: { icon: _jsx(IconSavedQuery, { fontSize: 24 }), visible: true, orderNumber: 4, isActive: allInitialPanelVisibility['TMSavedQuerySelector'] }
267
330
  }
268
- ], [tmTreeSelectorElement, showSearchResults, tmRecentsManagerElement, tmSearchQueryPanelElement, tmSavedQuerySelectorElement, fromDTD, mruTIDs]);
269
- return (_jsxs(_Fragment, { children: [showSearchResults ? _jsx(StyledMultiViewPanel, { "$isVisible": currentSearchView === TMSearchViews.Search, children: _jsx(TMPanelManagerWithPersistenceProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: initialPanelDimensions, initialDimensions: initialPanelDimensions, initialMobilePanelId: 'TMRecentsManager', isPersistenceEnabled: !isMobile ? hasSavedLayout() : false, persistPanelStates: !isMobile ? (state) => persistPanelStates(state) : undefined, persistedPanelStates: getPersistedPanelStates(), children: _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", showToolbar: true, minPanelSizePx: !isMobile ? 250 : 150 }) }) }) : tmSearchQueryPanelElement, showSearchResults && _jsx(TMSearchResult, { isVisible: isVisible && currentSearchView === TMSearchViews.Result, context: SearchResultContext.METADATA_SEARCH, searchResults: searchResult, floatingActionConfig: floatingActionConfig, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, openInOffice: openInOffice, onRefreshSearchAsyncDatagrid: onRefreshSearchAsyncDatagrid, onClose: () => { onlyShowSearchQueryPanel ? setShowSearchResults(false) : setCurrentSearchView(TMSearchViews.Search); }, onFileOpened: onFileOpened, onTaskCreateRequest: onTaskCreateRequest, openWGsCopyMoveForm: openWGsCopyMoveForm, editPdfForm: editPdfForm, onOpenPdfEditorRequest: onOpenPdfEditorRequest, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, openFileUploaderPdfEditor: openFileUploaderPdfEditor, passToArchiveCallback: passToArchiveCallback, onSelectedTIDChanged: onCurrentTIDChangedCallback, showTodoDcmtForm: showTodoDcmtForm, showToppyDraggableHelpCenter: showToppyDraggableHelpCenter, toppyHelpCenterUsePortal: toppyHelpCenterUsePortal, onReferenceClick: onReferenceClick, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, inputDID: inputDID, formAutoOpen: formAutoOpen, fetchRemoteCertificates: fetchRemoteCertificates, graphometricManager: graphometricManager })] }));
331
+ ], [tmTreeSelectorElement, showSearchResults, tmRecentsManagerElement, tmSearchQueryPanelElement, tmSavedQuerySelectorElement, fromDTD, mruTIDs, refreshRecentsAsync, refreshSavedQueriesAsync]);
332
+ // Quando è visibile solo il pannello di ricerca (es. modale di abbinamento molti a molti) serve
333
+ const singlePanelVisibility = { 'TMSearchQueryPanel': true };
334
+ const singlePanelDimensions = { 'TMSearchQueryPanel': { width: '100%', height: '100%' } };
335
+ const singlePanelDefinition = useMemo(() => [
336
+ {
337
+ id: 'TMSearchQueryPanel',
338
+ name: fromDTD?.nameLoc ?? SDKUI_Localizator.Search_Metadata,
339
+ contentOptions: { component: tmSearchQueryPanelElement },
340
+ toolbarOptions: { icon: _jsx(IconFilter, { fontSize: 24 }), visible: false, orderNumber: 1, isActive: true }
341
+ }
342
+ ], [tmSearchQueryPanelElement, fromDTD]);
343
+ return (_jsxs(_Fragment, { children: [onlyShowSearchQueryPanel
344
+ // Il pannello di ricerca resta montato anche quando sono a schermo i risultati: tornando
345
+ // indietro si ritrova l'ultima ricerca impostata, senza rimontaggi che ne resettano i filtri
346
+ ? _jsx(StyledMultiViewPanel, { "$isVisible": !showSearchResults, children: _jsx(TMPanelManagerProvider, { panels: singlePanelDefinition, initialVisibility: singlePanelVisibility, defaultDimensions: singlePanelDimensions, initialDimensions: singlePanelDimensions, initialMobilePanelId: 'TMSearchQueryPanel', children: tmSearchQueryPanelElement }) })
347
+ : _jsx(StyledMultiViewPanel, { "$isVisible": currentSearchView === TMSearchViews.Search, children: _jsx(TMPanelManagerWithPersistenceProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: initialPanelDimensions, initialDimensions: initialPanelDimensions, initialMobilePanelId: 'TMRecentsManager', isPersistenceEnabled: !isMobile ? hasSavedLayout() : false, persistPanelStates: !isMobile ? (state) => persistPanelStates(state) : undefined, persistedPanelStates: getPersistedPanelStates(), children: _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", showToolbar: true, minPanelSizePx: !isMobile ? 250 : 150 }) }) }), showSearchResults && _jsx(TMSearchResult, { isVisible: isVisible && currentSearchView === TMSearchViews.Result, context: SearchResultContext.METADATA_SEARCH, searchResults: searchResult, floatingActionConfig: floatingActionConfig, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, openInOffice: openInOffice, onRefreshSearchAsyncDatagrid: onRefreshSearchAsyncDatagrid, onClose: () => { if (onlyShowSearchQueryPanel)
348
+ setShowSearchResults(false); setCurrentSearchView(TMSearchViews.Search); }, backCaption: onlyShowSearchQueryPanel ? SDKUI_Localizator.BackToSearch : undefined, onFileOpened: onFileOpened, onTaskCreateRequest: onTaskCreateRequest, openWGsCopyMoveForm: openWGsCopyMoveForm, editPdfForm: editPdfForm, onOpenPdfEditorRequest: onOpenPdfEditorRequest, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, openFileUploaderPdfEditor: openFileUploaderPdfEditor, passToArchiveCallback: passToArchiveCallback, onSelectedTIDChanged: onCurrentTIDChangedCallback, showTodoDcmtForm: showTodoDcmtForm, showToppyDraggableHelpCenter: showToppyDraggableHelpCenter, toppyHelpCenterUsePortal: toppyHelpCenterUsePortal, onReferenceClick: onReferenceClick, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, inputDID: inputDID, formAutoOpen: formAutoOpen, fetchRemoteCertificates: fetchRemoteCertificates, graphometricManager: graphometricManager })] }));
270
349
  };
271
350
  export default TMSearch;
272
351
  const TMTreeSelectorWrapper = ({ isMobile, onSelectedTIDChanged }) => {
@@ -285,11 +364,11 @@ const TMRecentsManagerWrapper = ({ mruTIDs, currentMruTID, deviceType, onSelecte
285
364
  onDeletedTID?.(tid);
286
365
  } }));
287
366
  };
288
- const TMSearchQueryPanelWrapper = ({ fromDTD, SQD, isExpertMode, showBackToResultButton, onSearchCompleted, onSqdSaved, onBackToResult, passToArchiveCallback, inputMids, maxDcmtsToBeReturned }) => {
367
+ const TMSearchQueryPanelWrapper = ({ isSearchViewOnScreen, fromDTD, SQD, isExpertMode, showBackToResultButton, onSearchCompleted, onSqdSaved, onBackToResult, passToArchiveCallback, inputMids, maxDcmtsToBeReturned, onRefreshRequested, onDcmtTypeReloaded }) => {
289
368
  const { setPanelVisibilityById, toggleMaximize, countVisibleLeafPanels } = useTMPanelManagerContext();
290
369
  const deviceType = useDeviceType();
291
370
  const isMobile = deviceType === DeviceType.MOBILE;
292
- return (_jsx(TMSearchQueryPanel, { onClosePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('TMSearchQueryPanel', false) : undefined, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => toggleMaximize("TMSearchQueryPanel") : undefined, isExpertMode: isExpertMode, fromDTD: fromDTD, SQD: SQD, inputMids: inputMids, onSearchCompleted: onSearchCompleted, onSqdSaved: onSqdSaved, showBackToResultButton: showBackToResultButton, onBackToResult: onBackToResult, passToArchiveCallback: passToArchiveCallback, maxDcmtsToBeReturned: maxDcmtsToBeReturned }));
371
+ return (_jsx(TMSearchQueryPanel, { isSearchViewOnScreen: isSearchViewOnScreen, onClosePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('TMSearchQueryPanel', false) : undefined, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => toggleMaximize("TMSearchQueryPanel") : undefined, isExpertMode: isExpertMode, fromDTD: fromDTD, SQD: SQD, inputMids: inputMids, onSearchCompleted: onSearchCompleted, onRefreshRequested: onRefreshRequested, onDcmtTypeReloaded: onDcmtTypeReloaded, onSqdSaved: onSqdSaved, showBackToResultButton: showBackToResultButton, onBackToResult: onBackToResult, passToArchiveCallback: passToArchiveCallback, maxDcmtsToBeReturned: maxDcmtsToBeReturned }));
293
372
  };
294
373
  const TMSavedQuerySelectorWrapper = ({ items, selectedId, allowShowSearch, manageDefault, onRefreshData, onItemClick, onDeleted, refreshFavoriteSavedQueries }) => {
295
374
  const { setPanelVisibilityById } = useTMPanelManagerContext();
@@ -58,10 +58,12 @@ const TMSearchQueryEditor = ({ qd, dcmtTypesList = [], isExpertMode = SDKUI_Glob
58
58
  const handleItemSelect = useCallback((tid, mid) => {
59
59
  if (currentEditingMID !== mid)
60
60
  setCurrentEditingMID(mid);
61
- if (!focusedTidMid || mid !== focusedTidMid.mid) {
62
- setFocusedTidMid({ tid: tid, mid: mid });
61
+ if (!focusedTidMid || mid !== focusedTidMid.mid || tid !== focusedTidMid.tid) {
62
+ const newFocusedTidMid = { tid: tid, mid: mid };
63
+ setFocusedTidMid(newFocusedTidMid);
64
+ onFocusedMetadataChanged?.(newFocusedTidMid);
63
65
  }
64
- }, [currentEditingMID, focusedTidMid]);
66
+ }, [currentEditingMID, focusedTidMid, onFocusedMetadataChanged]);
65
67
  const handleAdvancedMenuClick = useCallback((e) => {
66
68
  if (e.button === AdvancedMenuButtons.MakeEditable && e.mid) {
67
69
  addOrRemoveEditableList(e.mid);
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { DcmtTypeDescriptor, QueryDescriptor, SavedQueryDescriptor, SearchResultDescriptor } from '@topconsultnpm/sdk-ts';
3
3
  interface ITMSearchQueryPanelProps {
4
+ isSearchViewOnScreen?: boolean;
4
5
  fromDTD?: DcmtTypeDescriptor;
5
6
  SQD?: SavedQueryDescriptor;
6
7
  isExpertMode?: boolean;
@@ -12,7 +13,7 @@ interface ITMSearchQueryPanelProps {
12
13
  onBack?: () => void;
13
14
  onBackToResult?: () => void;
14
15
  onSqdSaved?: (newSqd: SavedQueryDescriptor) => void;
15
- onSearchCompleted?: (searchResult: SearchResultDescriptor[], qd: QueryDescriptor | undefined) => void;
16
+ onSearchCompleted?: (searchResult: SearchResultDescriptor[], qd: QueryDescriptor | undefined, append?: boolean) => void;
16
17
  onClosePanel?: () => void;
17
18
  allowMaximize?: boolean;
18
19
  onMaximizePanel?: () => void;
@@ -21,10 +22,19 @@ interface ITMSearchQueryPanelProps {
21
22
  value: string;
22
23
  }>, tid?: number) => void;
23
24
  maxDcmtsToBeReturned?: number;
25
+ onRefreshRequested?: () => Promise<void>;
26
+ /** Notifica il tipo documento riletto dal server prima di ogni ricerca, così il chiamante allinea il proprio descrittore */
27
+ onDcmtTypeReloaded?: (dtd: DcmtTypeDescriptor) => void;
24
28
  }
25
29
  declare const TMSearchQueryPanel: React.FunctionComponent<ITMSearchQueryPanelProps>;
26
30
  export default TMSearchQueryPanel;
27
31
  export declare const refreshLastSearch: (qd: QueryDescriptor | undefined) => Promise<SearchResultDescriptor[] | undefined>;
28
- export declare const StyledToppyTextContainer: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> & Partial<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>> & string;
29
- export declare const StyledToppyText: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, never> & Partial<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, never>>> & string;
30
- export declare const StyledToppyImage: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<React.DetailedHTMLProps<React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, never> & Partial<Pick<React.DetailedHTMLProps<React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, never>>> & string;
32
+ export declare const StyledToppyTextContainer: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
33
+ style?: React.CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
34
+ }> & string;
35
+ export declare const StyledToppyText: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "style"> & {
36
+ style?: React.CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
37
+ }> & string;
38
+ export declare const StyledToppyImage: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<React.DetailedHTMLProps<React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, "style"> & {
39
+ style?: React.CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
40
+ }> & string;