@topconsultnpm/sdkui-react 6.22.0-dev2.3 → 6.22.0-dev2.30

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 (118) hide show
  1. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +1 -1
  2. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +1 -1
  3. package/lib/components/base/TMButton.d.ts +13 -0
  4. package/lib/components/base/TMButton.js +137 -5
  5. package/lib/components/base/TMDataGrid.d.ts +2 -0
  6. package/lib/components/base/TMDataGrid.js +81 -8
  7. package/lib/components/base/TMEditorBase.d.ts +2 -0
  8. package/lib/components/base/TMFileManager.js +5 -3
  9. package/lib/components/base/TMFileManagerUtils.d.ts +1 -0
  10. package/lib/components/base/TMFileManagerUtils.js +16 -0
  11. package/lib/components/base/TMModal.d.ts +4 -0
  12. package/lib/components/base/TMModal.js +42 -11
  13. package/lib/components/base/TMPanel.d.ts +1 -0
  14. package/lib/components/base/TMPanel.js +79 -20
  15. package/lib/components/base/TMPopUp.js +3 -0
  16. package/lib/components/base/TMTooltip.d.ts +2 -1
  17. package/lib/components/base/TMTooltip.js +23 -6
  18. package/lib/components/base/TMTreeView.js +108 -67
  19. package/lib/components/choosers/TMDcmtTypeChooser.js +4 -3
  20. package/lib/components/choosers/TMDistinctValues.d.ts +9 -7
  21. package/lib/components/choosers/TMDistinctValues.js +149 -142
  22. package/lib/components/choosers/TMMetadataChooser.js +1 -1
  23. package/lib/components/choosers/TMQuickSearchInfo.d.ts +12 -0
  24. package/lib/components/choosers/TMQuickSearchInfo.js +279 -0
  25. package/lib/components/choosers/TMQuickSearchSettingsForm.d.ts +16 -0
  26. package/lib/components/choosers/TMQuickSearchSettingsForm.js +94 -0
  27. package/lib/components/choosers/TMSelectedValuesSummary.d.ts +13 -0
  28. package/lib/components/choosers/TMSelectedValuesSummary.js +91 -0
  29. package/lib/components/editors/TMDropDown.d.ts +3 -0
  30. package/lib/components/editors/TMDropDown.js +197 -5
  31. package/lib/components/editors/TMMetadataEditor.d.ts +5 -1
  32. package/lib/components/editors/TMMetadataEditor.js +8 -3
  33. package/lib/components/editors/TMTextBox.js +2 -2
  34. package/lib/components/features/documents/TMBatchUpdateForm.js +19 -5
  35. package/lib/components/features/documents/TMDcmtBlog.d.ts +3 -0
  36. package/lib/components/features/documents/TMDcmtBlog.js +4 -4
  37. package/lib/components/features/documents/TMDcmtForm.d.ts +7 -0
  38. package/lib/components/features/documents/TMDcmtForm.js +112 -45
  39. package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +11 -0
  40. package/lib/components/features/documents/TMDcmtFormActionButtons.js +74 -7
  41. package/lib/components/features/documents/TMDcmtPreview.js +10 -6
  42. package/lib/components/features/documents/TMMasterDetailDcmts.js +95 -33
  43. package/lib/components/features/documents/TMMasterInfoFields.d.ts +19 -0
  44. package/lib/components/features/documents/TMMasterInfoFields.js +186 -0
  45. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +40 -0
  46. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +296 -0
  47. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +363 -0
  48. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.js +259 -0
  49. package/lib/components/features/documents/TMRelationViewer.d.ts +14 -1
  50. package/lib/components/features/documents/TMRelationViewer.js +69 -20
  51. package/lib/components/features/search/TMSearch.js +29 -16
  52. package/lib/components/features/search/TMSearchQueryEditor.js +5 -3
  53. package/lib/components/features/search/TMSearchQueryPanel.d.ts +1 -1
  54. package/lib/components/features/search/TMSearchQueryPanel.js +28 -7
  55. package/lib/components/features/search/TMSearchResult.d.ts +9 -0
  56. package/lib/components/features/search/TMSearchResult.js +419 -108
  57. package/lib/components/features/search/TMTreeSelector.js +18 -5
  58. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +10 -0
  59. package/lib/components/features/workflow/TMWorkflowPopup.js +8 -4
  60. package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +1 -0
  61. package/lib/components/layout/panelManager/TMPanelManagerContainer.js +24 -14
  62. package/lib/components/layout/panelManager/TMPanelManagerContext.js +68 -93
  63. package/lib/components/layout/panelManager/TMPanelWrapper.js +2 -2
  64. package/lib/components/layout/panelManager/types.d.ts +3 -0
  65. package/lib/components/layout/panelManager/utils.js +13 -11
  66. package/lib/components/viewers/TMMidViewer.js +4 -1
  67. package/lib/components/viewers/TMTidViewer.js +25 -11
  68. package/lib/helper/SDKUI_Globals.d.ts +82 -0
  69. package/lib/helper/SDKUI_Globals.js +119 -0
  70. package/lib/helper/SDKUI_Localizator.d.ts +24 -0
  71. package/lib/helper/SDKUI_Localizator.js +240 -0
  72. package/lib/helper/TMIcons.d.ts +1 -0
  73. package/lib/helper/TMIcons.js +3 -0
  74. package/lib/helper/dataGridSearchHelper.d.ts +28 -0
  75. package/lib/helper/dataGridSearchHelper.js +51 -0
  76. package/lib/helper/dcmtsHelper.d.ts +20 -0
  77. package/lib/helper/dcmtsHelper.js +58 -1
  78. package/lib/helper/helpers.d.ts +20 -0
  79. package/lib/helper/helpers.js +55 -1
  80. package/lib/helper/index.d.ts +1 -0
  81. package/lib/helper/index.js +1 -0
  82. package/lib/helper/queryHelper.d.ts +2 -0
  83. package/lib/helper/queryHelper.js +3 -1
  84. package/lib/hooks/tmDistinctValuesGridHelper.d.ts +16 -0
  85. package/lib/hooks/tmDistinctValuesGridHelper.js +31 -0
  86. package/lib/hooks/useArchiveListForm.d.ts +39 -0
  87. package/lib/hooks/useArchiveListForm.js +46 -0
  88. package/lib/hooks/useCaseFlowApprove.d.ts +56 -0
  89. package/lib/hooks/useCaseFlowApprove.js +157 -0
  90. package/lib/hooks/useDataUserIdItem.d.ts +1 -0
  91. package/lib/hooks/useDataUserIdItem.js +1 -0
  92. package/lib/hooks/useDocumentOperations.d.ts +2 -0
  93. package/lib/hooks/useDocumentOperations.js +28 -5
  94. package/lib/hooks/useMultiMasterDetailDcmts.d.ts +100 -0
  95. package/lib/hooks/useMultiMasterDetailDcmts.js +587 -0
  96. package/lib/hooks/useRelatedDocuments.js +2 -26
  97. package/lib/hooks/useTMDistinctValuesMetadataDisplay.d.ts +18 -0
  98. package/lib/hooks/useTMDistinctValuesMetadataDisplay.js +103 -0
  99. package/lib/hooks/useTMDistinctValuesQuickSearch.d.ts +49 -0
  100. package/lib/hooks/useTMDistinctValuesQuickSearch.js +307 -0
  101. package/lib/hooks/useTMDistinctValuesSelection.d.ts +42 -0
  102. package/lib/hooks/useTMDistinctValuesSelection.js +103 -0
  103. package/lib/hooks/useTMDistinctValuesSource.d.ts +29 -0
  104. package/lib/hooks/useTMDistinctValuesSource.js +105 -0
  105. package/lib/index.d.ts +1 -0
  106. package/lib/index.js +1 -0
  107. package/lib/services/caseflow/CaseFlowService.d.ts +236 -0
  108. package/lib/services/caseflow/CaseFlowService.js +693 -0
  109. package/lib/services/caseflow/CaseFlowTemplateCacheService.d.ts +28 -0
  110. package/lib/services/caseflow/CaseFlowTemplateCacheService.js +121 -0
  111. package/lib/services/caseflow/caseFlowNameCache.d.ts +32 -0
  112. package/lib/services/caseflow/caseFlowNameCache.js +116 -0
  113. package/lib/services/caseflow/caseFlowWorkItemUtils.d.ts +61 -0
  114. package/lib/services/caseflow/caseFlowWorkItemUtils.js +113 -0
  115. package/lib/services/index.d.ts +4 -0
  116. package/lib/services/index.js +4 -0
  117. package/lib/services/platform_services.d.ts +1 -1
  118. package/package.json +66 -66
@@ -0,0 +1,363 @@
1
+ import React from 'react';
2
+ import { DataListViewModes, DcmtTypeDescriptor, MetadataDescriptor, RelationDescriptor } from '@topconsultnpm/sdk-ts';
3
+ import { DataGridTypes, IColumnProps } from 'devextreme-react/data-grid';
4
+ import { TMPanelDimensionsMap } from '../../layout/panelManager/types';
5
+ import { DcmtInfo, MetadataValueDescriptorEx } from '../../../ts';
6
+ /** Relazione di dettaglio con il relativo tipo documento */
7
+ export interface DetailRelationItem {
8
+ relation: RelationDescriptor;
9
+ detailDtd: DcmtTypeDescriptor | undefined;
10
+ }
11
+ export interface MultiDetailStep {
12
+ phase: number;
13
+ label: React.ReactNode;
14
+ }
15
+ export type AccordionSection = 'masterInfo' | 'archivedDetails' | 'archiveList';
16
+ /**
17
+ * Stato del pannello che ospita una sezione. Lo espone il panel manager, il cui contesto è leggibile
18
+ * solo dentro l'albero del provider: da qui passa alle testate (vedi TMSummarySectionSlot)
19
+ */
20
+ export type SectionPanelState = {
21
+ isMaximized: boolean;
22
+ canMaximize: boolean;
23
+ canCollapse: boolean;
24
+ toggleMaximize: () => void;
25
+ };
26
+ /** Valore di un metadato letto da un documento: una cella del risultato di ricerca */
27
+ export type MetadataScalarValue = string | number | boolean | Date | null | undefined;
28
+ /**
29
+ * Riga del riepilogo: oltre ai campi di servizio (prefisso `__`) porta i valori dei metadati
30
+ * indicizzati per mid (`String(mid)`), come richiesto dal dataField delle colonne della griglia
31
+ */
32
+ export interface ArchiveRow {
33
+ /** Chiave della riga in griglia */
34
+ id: number;
35
+ /** Tipo documento di dettaglio a cui appartiene la riga */
36
+ __tid: number;
37
+ /** Valori compilati nel form, nel formato richiesto dall'archiviazione */
38
+ __values: Array<MetadataValueDescriptorEx>;
39
+ /** File da archiviare, se il tipo documento lo prevede */
40
+ __file?: File;
41
+ /** Valore del metadato mostrato in colonna, indicizzato per mid */
42
+ [mid: string]: string | number | Array<MetadataValueDescriptorEx> | File | undefined;
43
+ }
44
+ /**
45
+ * Cella nel render delle colonne del riepilogo: i valori dei metadati arrivano dal form come
46
+ * stringhe, quindi il `value` generico di DevExtreme si restringe
47
+ */
48
+ export type ArchiveRowCell = Omit<DataGridTypes.ColumnCellTemplateData<ArchiveRow, number>, 'value'> & {
49
+ readonly value?: string | number;
50
+ };
51
+ /**
52
+ * Modifiche di una riga in arrivo dalla griglia (mid -> nuovo valore): in modifica diretta ci sono
53
+ * i metadati testuali e numerici (vedi isInlineEditableMetadata), quindi stringhe e numeri,
54
+ * e l'editor svuotato restituisce null
55
+ */
56
+ export type ArchiveRowChanges = Record<string, string | number | null | undefined>;
57
+ /** Aggiornamento di una riga della griglia, con le sole modifiche possibili in linea */
58
+ export type ArchiveRowUpdatingEvent = Omit<DataGridTypes.RowUpdatingEvent<ArchiveRow, number>, 'newData'> & {
59
+ newData: ArchiveRowChanges;
60
+ };
61
+ export declare const SECTION_WEIGHTS: Record<AccordionSection, number>;
62
+ export declare const SECTION_HEADER_HEIGHT_PX = 30;
63
+ export declare const PANEL_GUTTER_PX = 10;
64
+ /** Il master è modificabile solo se il tipo documento lo consente */
65
+ export declare const canUpdateMasterCallback: (dtd?: DcmtTypeDescriptor, masterDcmt?: DcmtInfo) => boolean;
66
+ /** Permesso di archiviazione sul tipo documento di dettaglio */
67
+ export declare const canArchive: (dtd?: DcmtTypeDescriptor) => boolean;
68
+ /**
69
+ * Marcatore delle celle modificabili direttamente in griglia: il doppio clic le porta in modifica,
70
+ * quindi non deve aprire anche il form della riga
71
+ */
72
+ export declare const INLINE_EDITABLE_CELL_CLASS = "tm-cell-inline-editable";
73
+ /**
74
+ * Modifica diretta in griglia: testo libero e numeri. Liste dati, calcolati, numeratori e speciali
75
+ * hanno editor e vincoli propri, le date una formattazione dedicata: restano al form
76
+ */
77
+ export declare const isInlineEditableMetadata: (md: MetadataDescriptor) => boolean;
78
+ /**
79
+ * Valore di una cella numerica: l'editor della griglia vuole un numero, non la stringa che
80
+ * la riga porta in `__values` per l'archiviazione. Vuoto o non numerico: cella vuota
81
+ */
82
+ export declare const toGridNumber: (value: unknown) => number | undefined;
83
+ /** Colonne della griglia di riepilogo dai metadati (utente) del tipo documento */
84
+ export declare const buildColumnsFromDtd: (dtd: DcmtTypeDescriptor | undefined, renderDataListCell: (value: string | Date | number | undefined, dataListID: number, viewMode: DataListViewModes) => React.ReactElement) => Array<IColumnProps>;
85
+ export declare const getDetailDtdAsync: (detailTID: number | undefined) => Promise<DcmtTypeDescriptor | undefined>;
86
+ /** Nome visualizzato del tipo documento (localizzato se richiesto) */
87
+ export declare const getDtdDisplayName: (dtd: DcmtTypeDescriptor | undefined) => string;
88
+ /** Messaggio del blocco: con righe inserite il tipo documento non è più modificabile */
89
+ export declare const getBackLockedTitle: () => string;
90
+ /**
91
+ * Altezze dei pannelli impilati a partire dalle sezioni aperte:
92
+ * una sezione chiusa vale 0% e resta a schermo con la sola testata
93
+ * le aperte si spartiscono tutto lo spazio
94
+ */
95
+ export declare const sectionPanelHeights: (sections: Array<AccordionSection>, sectionsOpen: Record<AccordionSection, boolean>, currentDimensions?: TMPanelDimensionsMap) => TMPanelDimensionsMap;
96
+ export declare const multiDetailStyles: {
97
+ stepper: {
98
+ display: "flex";
99
+ alignItems: "center";
100
+ justifyContent: "center";
101
+ gap: string;
102
+ };
103
+ backArrow: {
104
+ display: "flex";
105
+ alignItems: "center";
106
+ justifyContent: "center";
107
+ width: string;
108
+ height: string;
109
+ borderRadius: string;
110
+ border: string;
111
+ color: string;
112
+ cursor: "pointer";
113
+ marginRight: string;
114
+ transition: "all 0.18s ease";
115
+ };
116
+ stepPill: {
117
+ display: "flex";
118
+ alignItems: "center";
119
+ gap: string;
120
+ padding: string;
121
+ borderRadius: string;
122
+ transition: "all 0.18s ease";
123
+ };
124
+ stepCircle: {
125
+ width: string;
126
+ height: string;
127
+ borderRadius: string;
128
+ color: "#ffffff";
129
+ display: "flex";
130
+ alignItems: "center";
131
+ justifyContent: "center";
132
+ fontSize: string;
133
+ fontWeight: number;
134
+ flexShrink: number;
135
+ transition: "all 0.18s ease";
136
+ };
137
+ stepLabel: {
138
+ fontSize: string;
139
+ whiteSpace: "nowrap";
140
+ display: "flex";
141
+ alignItems: "center";
142
+ };
143
+ stepConnector: {
144
+ width: string;
145
+ height: string;
146
+ margin: string;
147
+ borderRadius: string;
148
+ flexShrink: number;
149
+ };
150
+ stepTypeLabel: {
151
+ display: "flex";
152
+ alignItems: "center";
153
+ gap: string;
154
+ maxWidth: string;
155
+ };
156
+ stepTypeLabelText: {
157
+ overflow: "hidden";
158
+ textOverflow: "ellipsis";
159
+ whiteSpace: "nowrap";
160
+ };
161
+ selectContainer: {
162
+ display: "flex";
163
+ flexDirection: "column";
164
+ alignItems: "center";
165
+ flex: number;
166
+ gap: string;
167
+ overflow: "auto";
168
+ padding: string;
169
+ };
170
+ selectTitle: {
171
+ fontSize: string;
172
+ fontWeight: number;
173
+ color: string;
174
+ textAlign: "center";
175
+ marginBottom: string;
176
+ };
177
+ selectList: {
178
+ display: "flex";
179
+ flexDirection: "column";
180
+ gap: string;
181
+ width: string;
182
+ maxWidth: string;
183
+ };
184
+ typeCard: {
185
+ display: "flex";
186
+ alignItems: "center";
187
+ gap: string;
188
+ padding: string;
189
+ borderRadius: string;
190
+ cursor: "pointer";
191
+ boxShadow: "0 1px 3px rgba(0, 0, 0, 0.06)";
192
+ transition: "all 0.15s ease";
193
+ };
194
+ typeCardIcon: {
195
+ width: string;
196
+ height: string;
197
+ borderRadius: string;
198
+ background: string;
199
+ display: "flex";
200
+ alignItems: "center";
201
+ justifyContent: "center";
202
+ flexShrink: number;
203
+ };
204
+ typeCardName: {
205
+ flex: number;
206
+ fontSize: string;
207
+ fontWeight: number;
208
+ color: string;
209
+ whiteSpace: "normal";
210
+ wordBreak: "break-word";
211
+ lineHeight: number;
212
+ };
213
+ };
214
+ export declare const accordionStyles: {
215
+ accordion: {
216
+ display: "flex";
217
+ flexDirection: "column";
218
+ minHeight: number;
219
+ borderRadius: string;
220
+ border: string;
221
+ background: string;
222
+ overflow: "hidden";
223
+ };
224
+ accordionInPanel: {
225
+ flex: number;
226
+ };
227
+ accordionHeader: {
228
+ display: "flex";
229
+ alignItems: "center";
230
+ gap: string;
231
+ padding: string;
232
+ cursor: "pointer";
233
+ userSelect: "none";
234
+ transition: "background 0.15s ease";
235
+ outline: string;
236
+ flexShrink: number;
237
+ minHeight: string;
238
+ };
239
+ accordionTitle: {
240
+ flex: number;
241
+ fontSize: string;
242
+ fontWeight: number;
243
+ color: string;
244
+ display: "flex";
245
+ alignItems: "center";
246
+ gap: string;
247
+ minWidth: number;
248
+ };
249
+ accordionBadge: {
250
+ display: "inline-flex";
251
+ alignItems: "center";
252
+ justifyContent: "center";
253
+ color: string;
254
+ fontSize: string;
255
+ fontWeight: number;
256
+ flexShrink: number;
257
+ };
258
+ accordionListBody: {
259
+ position: "relative";
260
+ flex: number;
261
+ minHeight: number;
262
+ display: "flex";
263
+ flexDirection: "column";
264
+ borderTop: string;
265
+ };
266
+ accordionListPlaceholder: {
267
+ display: "flex";
268
+ flex: number;
269
+ alignItems: "center";
270
+ justifyContent: "center";
271
+ gap: string;
272
+ padding: string;
273
+ color: string;
274
+ fontSize: string;
275
+ };
276
+ accordionExpandBtn: {
277
+ display: "inline-flex";
278
+ alignItems: "center";
279
+ justifyContent: "center";
280
+ width: string;
281
+ height: string;
282
+ padding: number;
283
+ borderRadius: string;
284
+ border: string;
285
+ background: string;
286
+ color: string;
287
+ cursor: "pointer";
288
+ flexShrink: number;
289
+ transition: "background 0.15s ease, color 0.15s ease";
290
+ };
291
+ };
292
+ export interface RenderStepperParams {
293
+ /** Passi da mostrare, in ordine di fase */
294
+ steps: Array<MultiDetailStep>;
295
+ /** Fase corrente: i passi con fase minore sono completati */
296
+ phase: number;
297
+ /** Con un solo tipo documento il numero dello step non si mostra */
298
+ hasMultipleTypes: boolean;
299
+ /** Con righe inserite il ritorno alla scelta del tipo è bloccato (freccia e step completato) */
300
+ isBackLocked: boolean;
301
+ /** La freccia di ritorno si mostra solo dove ha senso tornare indietro */
302
+ showBackArrow: boolean;
303
+ /** Ritorno indietro dalla freccia */
304
+ onBack: () => void;
305
+ /** Click su uno step completato: riceve la fase di destinazione */
306
+ onStepClick: (phase: number) => void;
307
+ }
308
+ export declare const renderStepper: ({ steps, phase, hasMultipleTypes, isBackLocked, showBackArrow, onBack, onStepClick }: RenderStepperParams) => import("react/jsx-runtime").JSX.Element;
309
+ export interface RenderSelectDcmtTypeParams {
310
+ /** Relazioni di dettaglio fra cui scegliere */
311
+ detailRelationItems: Array<DetailRelationItem>;
312
+ /** Relazione attualmente selezionata */
313
+ selectedRelation: RelationDescriptor | undefined;
314
+ /** Selezione di una relazione */
315
+ onSelectRelation: (item: DetailRelationItem) => void;
316
+ }
317
+ export declare const renderSelectDcmtType: ({ detailRelationItems, selectedRelation, onSelectRelation }: RenderSelectDcmtTypeParams) => import("react/jsx-runtime").JSX.Element;
318
+ export interface RenderAccordionHeaderParams {
319
+ /** Sezione a cui appartiene la testata */
320
+ section: AccordionSection;
321
+ /** Sezione aperta o collassata */
322
+ isOpen: boolean;
323
+ /** Tooltip del collasso */
324
+ tooltip: string;
325
+ /** Conteggio mostrato nel badge */
326
+ count: number;
327
+ /** Titolo della sezione (icona + testo) */
328
+ title: React.ReactNode;
329
+ /** Pulsanti specifici della sezione, mostrati prima di quello di ingrandimento */
330
+ actions?: React.ReactNode;
331
+ /** Stato del pannello che ospita la sezione: l'ingrandimento è quello del panel manager */
332
+ panel: SectionPanelState;
333
+ /** Apre/chiude la sezione */
334
+ onToggleOpen: (section: AccordionSection, isOpen: boolean) => void;
335
+ }
336
+ export declare const renderAccordionHeader: ({ section, isOpen, tooltip, count, title, actions, panel, onToggleOpen }: RenderAccordionHeaderParams) => import("react/jsx-runtime").JSX.Element;
337
+ /**
338
+ * Contenuto di un pannello: il contesto del panel manager è leggibile solo dentro l'albero del
339
+ * provider, quindi è qui che si prende lo stato di ingrandimento da passare alla sezione
340
+ */
341
+ export declare const TMSummarySectionSlot: ({ section, render, onBeforeMaximize }: {
342
+ section: AccordionSection;
343
+ render: (panel: SectionPanelState) => React.ReactNode;
344
+ onBeforeMaximize?: (section: AccordionSection) => void;
345
+ }) => import("react/jsx-runtime").JSX.Element;
346
+ /**
347
+ * Segnala che l'utente ha spostato un separatore: è l'unico caso in cui le altezze dei pannelli sono
348
+ * una sua scelta, quindi la sola da salvare. Le quote calcolate all'apertura del riepilogo o al
349
+ * collasso di una sezione non vanno scritte nel local storage.
350
+ * Vive dentro il provider perché il contesto è leggibile solo lì
351
+ */
352
+ export declare const TMSummaryResizeTracker: ({ onUserResize }: {
353
+ onUserResize: () => void;
354
+ }) => null;
355
+ /**
356
+ * Tiene allineate le altezze dei pannelli al collasso delle sezioni: il panel manager non
357
+ * conosce il collasso, quindi è qui che l'apertura di una sezione si traduce nelle nuove quote.
358
+ * Vive dentro il provider perché il contesto è leggibile solo lì
359
+ */
360
+ export declare const TMSectionPanelsHeights: ({ sections, sectionsOpen }: {
361
+ sections: Array<AccordionSection>;
362
+ sectionsOpen: Record<AccordionSection, boolean>;
363
+ }) => null;
@@ -0,0 +1,259 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import React, { useEffect, useRef } from 'react';
3
+ import { AccessLevelsEx, DataListViewModes, DcmtTypeListCacheService, MetadataDataDomains, MetadataDataTypes, SDK_Globals } from '@topconsultnpm/sdk-ts';
4
+ import { hoverStyle, IconChevronRight, IconWindowMaximize, IconWindowMinimize, SDKUI_Localizator } from '../../../helper';
5
+ import { formatScalarValue, getUserMetadataSorted } from '../../../helper/dcmtsHelper';
6
+ import { TMColors } from '../../../utils/theme';
7
+ import { TMDcmtTypeIcon } from '../../viewers/TMTidViewer';
8
+ import TMTooltip from '../../base/TMTooltip';
9
+ import { DeviceType, useDeviceType } from '../../base/TMDeviceProvider';
10
+ import { useTMPanelManagerContext } from '../../layout/panelManager/TMPanelManagerContext';
11
+ // l'elenco da archiviare è l'informazione più importante, quindi prende la fetta maggiore
12
+ export const SECTION_WEIGHTS = {
13
+ masterInfo: 25,
14
+ archivedDetails: 30,
15
+ archiveList: 45
16
+ };
17
+ export const SECTION_HEADER_HEIGHT_PX = 30;
18
+ // Spessore dei separatori fra i pannelli
19
+ export const PANEL_GUTTER_PX = 10;
20
+ // =================================================================================================
21
+ // HELPER
22
+ // =================================================================================================
23
+ /** Il master è modificabile solo se il tipo documento lo consente */
24
+ export const canUpdateMasterCallback = (dtd, masterDcmt) => (dtd?.perm?.canUpdate === AccessLevelsEx.Yes || dtd?.perm?.canUpdate === AccessLevelsEx.Mixed)
25
+ && masterDcmt?.TID !== undefined && masterDcmt?.DID !== undefined;
26
+ /** Permesso di archiviazione sul tipo documento di dettaglio */
27
+ export const canArchive = (dtd) => dtd?.perm?.canArchive === AccessLevelsEx.Yes || dtd?.perm?.canArchive === AccessLevelsEx.Mixed;
28
+ /**
29
+ * Marcatore delle celle modificabili direttamente in griglia: il doppio clic le porta in modifica,
30
+ * quindi non deve aprire anche il form della riga
31
+ */
32
+ export const INLINE_EDITABLE_CELL_CLASS = 'tm-cell-inline-editable';
33
+ /**
34
+ * Modifica diretta in griglia: testo libero e numeri. Liste dati, calcolati, numeratori e speciali
35
+ * hanno editor e vincoli propri, le date una formattazione dedicata: restano al form
36
+ */
37
+ export const isInlineEditableMetadata = (md) => (md.dataType === MetadataDataTypes.Varchar || md.dataType === MetadataDataTypes.Number)
38
+ && (md.dataDomain === undefined || md.dataDomain === MetadataDataDomains.None)
39
+ && md.isSystem !== 1 && md.isSystemDerived !== 1;
40
+ /**
41
+ * Valore di una cella numerica: l'editor della griglia vuole un numero, non la stringa che
42
+ * la riga porta in `__values` per l'archiviazione. Vuoto o non numerico: cella vuota
43
+ */
44
+ export const toGridNumber = (value) => {
45
+ if (value === undefined || value === null || value === '')
46
+ return undefined;
47
+ const parsed = typeof value === 'number' ? value : Number(value);
48
+ return Number.isFinite(parsed) ? parsed : undefined;
49
+ };
50
+ /** Colonne della griglia di riepilogo dai metadati (utente) del tipo documento */
51
+ export const buildColumnsFromDtd = (dtd, renderDataListCell) => getUserMetadataSorted(dtd).map(md => {
52
+ const dataListID = md.dataListID ?? 0;
53
+ const isDataList = md.dataDomain === MetadataDataDomains.DataList && dataListID > 0;
54
+ const viewMode = md.dataListViewMode ?? DataListViewModes.None;
55
+ const dataType = md.dataType;
56
+ const format = md.format?.format;
57
+ const formatCulture = md.format?.formatCulture;
58
+ const isInlineEditable = isInlineEditableMetadata(md);
59
+ const isNumber = dataType === MetadataDataTypes.Number;
60
+ // Date e numeri usano la formattazione scalare; le liste dati il render comune. La cella
61
+ // modificabile mostra sempre l'editor, quindi non ha un proprio render
62
+ const needsScalarFormat = !isDataList && !isInlineEditable && (dataType === MetadataDataTypes.DateTime || isNumber);
63
+ return {
64
+ dataField: String(md.id),
65
+ caption: (SDK_Globals.useLocalizedName ? md.nameLoc : md.name) ?? md.name ?? '',
66
+ // La colonna modificabile dichiara il tipo: senza valori DevExtreme non saprebbe che editor usare
67
+ ...(isInlineEditable
68
+ ? {
69
+ // I numeri arrivano in cella già come numeri (vedi buildArchiveRow): l'editor è la casella numerica
70
+ dataType: isNumber ? 'number' : 'string',
71
+ allowEditing: true,
72
+ showEditorAlways: true,
73
+ cssClass: INLINE_EDITABLE_CELL_CLASS,
74
+ // Lunghezza e obbligatorietà del metadato valgono anche in griglia; sui numeri
75
+ // i limiti restano all'API, in cella basta che sia un numero
76
+ editorOptions: !isNumber && md.length ? { maxLength: md.length } : undefined,
77
+ validationRules: String(md.isRequired) === '1' ? [{ type: 'required', message: SDKUI_Localizator.RequiredField }] : undefined,
78
+ }
79
+ : { allowEditing: false }),
80
+ cellRender: isDataList
81
+ ? (cellData) => renderDataListCell(cellData.value, dataListID, viewMode)
82
+ : (needsScalarFormat ? (cellData) => formatScalarValue(cellData.value, dataType, format, formatCulture) : undefined),
83
+ };
84
+ });
85
+ // Accesso al descrittore del tipo documento di dettaglio
86
+ export const getDetailDtdAsync = (detailTID) => detailTID === undefined ? Promise.resolve(undefined) : DcmtTypeListCacheService.GetWithNotGrantedAsync(detailTID, undefined);
87
+ /** Nome visualizzato del tipo documento (localizzato se richiesto) */
88
+ export const getDtdDisplayName = (dtd) => {
89
+ if (!dtd)
90
+ return '';
91
+ return (SDK_Globals.useLocalizedName ? dtd.nameLoc : dtd.name) ?? dtd.name ?? '';
92
+ };
93
+ /** Messaggio del blocco: con righe inserite il tipo documento non è più modificabile */
94
+ export const getBackLockedTitle = () => SDKUI_Localizator.DeleteAllRowsToChangeDcmtType;
95
+ /**
96
+ * Altezze dei pannelli impilati a partire dalle sezioni aperte:
97
+ * una sezione chiusa vale 0% e resta a schermo con la sola testata
98
+ * le aperte si spartiscono tutto lo spazio
99
+ */
100
+ export const sectionPanelHeights = (sections, sectionsOpen, currentDimensions) => {
101
+ const weightOf = (section) => {
102
+ if (!sectionsOpen[section])
103
+ return 0;
104
+ const current = parseFloat(currentDimensions?.[section]?.height ?? '');
105
+ // Sezione che si apre ora (era a 0%) o prima apertura: si riparte dalla quota nominale
106
+ return Number.isFinite(current) && current > 0 ? current : SECTION_WEIGHTS[section];
107
+ };
108
+ const total = sections.reduce((sum, section) => sum + weightOf(section), 0);
109
+ return sections.reduce((acc, section) => {
110
+ acc[section] = { width: '100%', height: total > 0 ? `${(weightOf(section) / total) * 100}%` : '0%' };
111
+ return acc;
112
+ }, {});
113
+ };
114
+ // =================================================================================================
115
+ // STILI
116
+ // =================================================================================================
117
+ export const multiDetailStyles = {
118
+ // Stepper
119
+ stepper: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '4px' },
120
+ backArrow: { display: 'flex', alignItems: 'center', justifyContent: 'center', width: '26px', height: '26px', borderRadius: '50%', border: `1.5px solid ${TMColors.primary}`, color: TMColors.primary, cursor: 'pointer', marginRight: '8px', transition: 'all 0.18s ease' },
121
+ stepPill: { display: 'flex', alignItems: 'center', gap: '7px', padding: '3px 10px 3px 4px', borderRadius: '16px', transition: 'all 0.18s ease' },
122
+ stepCircle: { width: '22px', height: '22px', borderRadius: '50%', color: '#ffffff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '12px', fontWeight: 600, flexShrink: 0, transition: 'all 0.18s ease' },
123
+ stepLabel: { fontSize: '12px', whiteSpace: 'nowrap', display: 'flex', alignItems: 'center' },
124
+ stepConnector: { width: '18px', height: '2px', margin: '0 5px', borderRadius: '1px', flexShrink: 0 },
125
+ stepTypeLabel: { display: 'flex', alignItems: 'center', gap: '6px', maxWidth: '260px' },
126
+ stepTypeLabelText: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
127
+ // Fase 1 - Selezione tipo documento
128
+ selectContainer: { display: 'flex', flexDirection: 'column', alignItems: 'center', flex: 1, gap: '8px', overflow: 'auto', padding: '8px 16px 24px' },
129
+ selectTitle: { fontSize: '18px', fontWeight: 700, color: TMColors.text_normal, textAlign: 'center', marginBottom: '16px' },
130
+ selectList: { display: 'flex', flexDirection: 'column', gap: '8px', width: '100%', maxWidth: '640px' },
131
+ typeCard: { display: 'flex', alignItems: 'center', gap: '12px', padding: '10px 14px', borderRadius: '9px', cursor: 'pointer', boxShadow: '0 1px 3px rgba(0, 0, 0, 0.06)', transition: 'all 0.15s ease' },
132
+ typeCardIcon: { width: '34px', height: '34px', borderRadius: '9px', background: TMColors.primary_container, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 },
133
+ typeCardName: { flex: 1, fontSize: '14px', fontWeight: 500, color: TMColors.text_normal, whiteSpace: 'normal', wordBreak: 'break-word', lineHeight: 1.3 },
134
+ };
135
+ // Stili delle sezioni collassabili
136
+ export const accordionStyles = {
137
+ accordion: { display: 'flex', flexDirection: 'column', minHeight: 0, borderRadius: '8px', border: `1px solid ${TMColors.card_background}`, background: TMColors.default_background, overflow: 'hidden' },
138
+ accordionInPanel: { flex: 1 },
139
+ accordionHeader: { display: 'flex', alignItems: 'center', gap: '8px', padding: '4px 8px', cursor: 'pointer', userSelect: 'none', transition: 'background 0.15s ease', outline: 'none', flexShrink: 0, minHeight: '28px' },
140
+ accordionTitle: { flex: 1, fontSize: '12px', fontWeight: 600, color: TMColors.text_normal, display: 'flex', alignItems: 'center', gap: '6px', minWidth: 0 },
141
+ accordionBadge: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', color: TMColors.primary, fontSize: '13px', fontWeight: 700, flexShrink: 0 },
142
+ accordionListBody: { position: 'relative', flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', borderTop: `1px solid ${TMColors.card_background}` },
143
+ accordionListPlaceholder: { display: 'flex', flex: 1, alignItems: 'center', justifyContent: 'center', gap: '10px', padding: '16px', color: TMColors.label_normal, fontSize: '13px' },
144
+ accordionExpandBtn: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: '20px', height: '20px', padding: 0, borderRadius: '6px', border: 'none', background: 'transparent', color: TMColors.label_normal, cursor: 'pointer', flexShrink: 0, transition: 'background 0.15s ease, color 0.15s ease' },
145
+ };
146
+ export const renderStepper = ({ steps, phase, hasMultipleTypes, isBackLocked, showBackArrow, onBack, onStepClick }) => (_jsxs("div", { style: multiDetailStyles.stepper, children: [showBackArrow && (_jsx(TMTooltip, { content: isBackLocked ? getBackLockedTitle() : SDKUI_Localizator.Back, parentStyle: { marginRight: '10px' }, children: _jsx("div", { onClick: isBackLocked ? undefined : onBack, style: {
147
+ ...multiDetailStyles.backArrow,
148
+ marginRight: 0,
149
+ ...(isBackLocked ? { borderColor: TMColors.disabled, color: TMColors.disabled, background: TMColors.card_background, opacity: 0.55, cursor: 'default' } : {}),
150
+ }, ...(isBackLocked ? {} : hoverStyle({ background: TMColors.primary, color: '#ffffff', transform: 'translateX(-2px)' }, { background: 'transparent', color: TMColors.primary, transform: 'translateX(0)' })), children: _jsx("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", style: { display: 'block' }, children: _jsx("path", { d: "M15 5l-7 7 7 7", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }) })), steps.map((step, index) => {
151
+ const isActive = step.phase === phase;
152
+ const isCompleted = step.phase < phase;
153
+ // Completato: verde con spunta. Corrente: blu. Da fare: grigio disabilitato
154
+ const accentColor = isCompleted ? TMColors.success : (isActive ? TMColors.primary : TMColors.disabled);
155
+ // Step completato cliccabile per tornare indietro, salvo il lock per righe presenti
156
+ const isClickable = isCompleted && !isBackLocked;
157
+ // Tooltip esplicativo solo sullo step completato quando il ritorno è bloccato dalle righe
158
+ const showLockTooltip = isCompleted && isBackLocked;
159
+ const stepPill = (_jsxs("div", { onClick: isClickable ? () => onStepClick(step.phase) : undefined, style: {
160
+ ...multiDetailStyles.stepPill,
161
+ background: isActive ? TMColors.primary_container : 'transparent',
162
+ boxShadow: isActive ? `inset 0 0 0 1.5px ${TMColors.primary}` : 'none',
163
+ cursor: isClickable ? 'pointer' : 'default',
164
+ ...(showLockTooltip ? { opacity: 0.5, filter: 'grayscale(0.6)' } : {}),
165
+ }, ...(isClickable && !isActive
166
+ ? hoverStyle({ background: TMColors.primary_container, transform: 'translateY(-1px)' }, { background: 'transparent', transform: 'translateY(0)' })
167
+ : {}), children: [hasMultipleTypes && (_jsx("div", { style: { ...multiDetailStyles.stepCircle, background: accentColor, boxShadow: isActive ? `0 2px 6px ${TMColors.primary}55` : 'none' }, children: isCompleted
168
+ ? (_jsx("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", style: { display: 'block' }, children: _jsx("path", { d: "M5 13l4 4L19 7", stroke: "#ffffff", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }) }))
169
+ : step.phase + 1 })), _jsx("span", { style: { ...multiDetailStyles.stepLabel, fontWeight: isActive ? 700 : 500, color: accentColor }, children: step.label })] }));
170
+ return (_jsxs(React.Fragment, { children: [showLockTooltip
171
+ ? _jsx(TMTooltip, { content: getBackLockedTitle(), children: stepPill })
172
+ : stepPill, index < steps.length - 1 && (_jsx("div", { style: { ...multiDetailStyles.stepConnector, background: isCompleted ? TMColors.success : TMColors.disabled } }))] }, step.phase));
173
+ })] }));
174
+ export const renderSelectDcmtType = ({ detailRelationItems, selectedRelation, onSelectRelation }) => (_jsxs("div", { style: multiDetailStyles.selectContainer, children: [_jsx("div", { style: multiDetailStyles.selectTitle, children: SDKUI_Localizator.SelectDcmtTypeForDetailArchiving }), _jsx("div", { style: multiDetailStyles.selectList, children: detailRelationItems.map((item) => {
175
+ const isSelected = item.relation === selectedRelation;
176
+ return (_jsxs("div", { onClick: () => onSelectRelation(item), style: {
177
+ ...multiDetailStyles.typeCard,
178
+ border: `1.5px solid ${isSelected ? TMColors.primary : TMColors.card_background}`,
179
+ background: isSelected ? TMColors.primary_container : TMColors.default_background,
180
+ }, ...hoverStyle({ borderColor: TMColors.primary, boxShadow: '0 4px 12px rgba(37, 89, 165, 0.18)' }, { borderColor: isSelected ? TMColors.primary : TMColors.card_background, boxShadow: '0 1px 3px rgba(0, 0, 0, 0.06)' }), children: [_jsx("div", { style: multiDetailStyles.typeCardIcon, children: _jsx(TMDcmtTypeIcon, { dtd: item.detailDtd }) }), _jsx("span", { style: multiDetailStyles.typeCardName, children: getDtdDisplayName(item.detailDtd) }), _jsx(IconChevronRight, { fontSize: 18, color: TMColors.label_normal })] }, item.relation.id ?? item.relation.detailTID));
181
+ }) })] }));
182
+ export const renderAccordionHeader = ({ section, isOpen, tooltip, count, title, actions, panel, onToggleOpen }) => {
183
+ const restBackground = isOpen ? TMColors.toolbar_background : 'transparent';
184
+ // Un pannello ingrandito non si collassa: resterebbe la sola testata al posto di tutto il riepilogo.
185
+ // Dove i pannelli si vedono uno alla volta (mobile) il collasso è precluso per lo stesso motivo
186
+ const canToggle = panel.canCollapse && !panel.isMaximized;
187
+ // Con un pannello alla volta l'ingrandimento non ha nulla da nascondere
188
+ const canMaximize = panel.canMaximize;
189
+ const onToggle = () => onToggleOpen(section, !isOpen);
190
+ const expandTooltip = panel.isMaximized ? SDKUI_Localizator.Minimize : SDKUI_Localizator.ZoomIn;
191
+ return (_jsxs("div", { role: canToggle ? 'button' : undefined, tabIndex: canToggle ? 0 : undefined, "aria-expanded": canToggle ? isOpen : undefined, style: { ...accordionStyles.accordionHeader, background: restBackground, ...(canToggle ? {} : { cursor: 'default' }) }, onClick: canToggle ? onToggle : undefined, onDoubleClick: canMaximize ? () => panel.toggleMaximize() : undefined, onKeyDown: canToggle ? (e) => { if (e.key === 'Enter' || e.key === ' ') {
192
+ e.preventDefault();
193
+ onToggle();
194
+ } } : undefined, ...(canToggle ? hoverStyle({ background: TMColors.primary_container }, { background: restBackground }) : {}), children: [_jsx(TMTooltip, { content: canToggle ? tooltip : undefined, parentStyle: { flex: 1, minWidth: 0 }, childStyle: { maxWidth: '100%' }, children: _jsxs("span", { style: accordionStyles.accordionTitle, children: [title, _jsx("span", { style: accordionStyles.accordionBadge, children: count })] }) }), actions, canMaximize && (_jsx(TMTooltip, { content: expandTooltip, children: _jsx("button", { type: 'button', onClick: (e) => { e.stopPropagation(); panel.toggleMaximize(); }, style: accordionStyles.accordionExpandBtn, "aria-label": expandTooltip, ...hoverStyle({ background: TMColors.primary_container, color: TMColors.primary }, { background: 'transparent', color: TMColors.label_normal }), children: panel.isMaximized ? _jsx(IconWindowMinimize, { fontSize: 14 }) : _jsx(IconWindowMaximize, { fontSize: 14 }) }) })), canToggle && (_jsx(IconChevronRight, { fontSize: 16, color: TMColors.label_normal, style: { transform: isOpen ? 'rotate(90deg)' : 'none', transition: 'transform 0.2s ease', flexShrink: 0 } }))] }));
195
+ };
196
+ /**
197
+ * Contenuto di un pannello: il contesto del panel manager è leggibile solo dentro l'albero del
198
+ * provider, quindi è qui che si prende lo stato di ingrandimento da passare alla sezione
199
+ */
200
+ export const TMSummarySectionSlot = ({ section, render, onBeforeMaximize }) => {
201
+ const { maximizedPanels, toggleMaximize } = useTMPanelManagerContext();
202
+ const isMaximized = maximizedPanels.includes(section);
203
+ // Su mobile il panel manager mostra un pannello alla volta: la sezione è già a tutto schermo, e
204
+ // ingrandirla nasconderebbe la barra con cui si passa da una sezione all'altra; chiuderla lascerebbe
205
+ // a schermo la sola testata, perché non ci sono altre sezioni a cui cedere lo spazio
206
+ const isMobile = useDeviceType() === DeviceType.MOBILE;
207
+ // Una sezione collassata non ha corpo: ingrandirla mostrerebbe un pannello vuoto, senza
208
+ // nemmeno poterla riaprire (da ingrandita il collasso è bloccato), quindi la si apre prima
209
+ const toggleMaximizeSection = () => {
210
+ if (!isMaximized)
211
+ onBeforeMaximize?.(section);
212
+ toggleMaximize(section);
213
+ };
214
+ return _jsx(_Fragment, { children: render({ isMaximized, canMaximize: !isMobile, canCollapse: !isMobile, toggleMaximize: toggleMaximizeSection }) });
215
+ };
216
+ /**
217
+ * Segnala che l'utente ha spostato un separatore: è l'unico caso in cui le altezze dei pannelli sono
218
+ * una sua scelta, quindi la sola da salvare. Le quote calcolate all'apertura del riepilogo o al
219
+ * collasso di una sezione non vanno scritte nel local storage.
220
+ * Vive dentro il provider perché il contesto è leggibile solo lì
221
+ */
222
+ export const TMSummaryResizeTracker = ({ onUserResize }) => {
223
+ const { isResizingActive } = useTMPanelManagerContext();
224
+ useEffect(() => {
225
+ if (isResizingActive)
226
+ onUserResize();
227
+ }, [isResizingActive]);
228
+ return null;
229
+ };
230
+ /**
231
+ * Tiene allineate le altezze dei pannelli al collasso delle sezioni: il panel manager non
232
+ * conosce il collasso, quindi è qui che l'apertura di una sezione si traduce nelle nuove quote.
233
+ * Vive dentro il provider perché il contesto è leggibile solo lì
234
+ */
235
+ export const TMSectionPanelsHeights = ({ sections, sectionsOpen }) => {
236
+ const { panelDimensions, panelVisibility, setPanelDimensionsById, maximizedPanels } = useTMPanelManagerContext();
237
+ // Con un pannello ingrandito le quote sono quelle dell'ingrandimento (100% e 0%): riallinearle al
238
+ // collasso lo svuoterebbe, quindi si aspetta il ritorno alla vista normale per rifare i conti
239
+ const hasMaximizedPanel = maximizedPanels.length > 0;
240
+ // Le altezze correnti si leggono da un ref: fra le dipendenze rientrerebbero a ogni ridimensionamento,
241
+ // mentre qui interessa solo il collasso
242
+ const dimensionsRef = useRef(panelDimensions);
243
+ dimensionsRef.current = panelDimensions;
244
+ // Le prime altezze le imposta il provider da initialDimensions, già calcolate sul collasso corrente
245
+ const isFirstRun = useRef(true);
246
+ useEffect(() => {
247
+ if (isFirstRun.current) {
248
+ isFirstRun.current = false;
249
+ return;
250
+ }
251
+ if (hasMaximizedPanel)
252
+ return;
253
+ // Solo i pannelli a schermo si spartiscono l'altezza, altrimenti resterebbe vuoto lo spazio dei nascosti
254
+ const visibleSections = sections.filter(section => panelVisibility[section] !== false);
255
+ const heights = sectionPanelHeights(visibleSections, sectionsOpen, dimensionsRef.current);
256
+ visibleSections.forEach(section => setPanelDimensionsById(section, heights[section].width, heights[section].height));
257
+ }, [sectionsOpen, hasMaximizedPanel, panelVisibility]);
258
+ return null;
259
+ };
@@ -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;