@bit.rhplus/ui.grid-layout 0.0.3 → 0.0.5
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.
- package/ColumnEditorModal.jsx +426 -369
- package/dist/ColumnEditorModal.js +134 -88
- package/dist/ColumnEditorModal.js.map +1 -1
- package/dist/useGridLayout.d.ts +1 -1
- package/dist/useGridLayout.js +1190 -233
- package/dist/useGridLayout.js.map +1 -1
- package/dist/useGridLayoutApi.d.ts +1 -1
- package/dist/useGridLayoutApi.js +102 -65
- package/dist/useGridLayoutApi.js.map +1 -1
- package/gridLayout.js +106 -106
- package/package.json +2 -2
- package/useGridLayout.js +1788 -625
- package/useGridLayoutApi.js +382 -296
- /package/dist/{preview-1755033542068.js → preview-1756735815679.js} +0 -0
package/dist/useGridLayout.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
|
7
7
|
import { useGridLayoutApi } from './useGridLayoutApi';
|
|
8
8
|
import { debounce } from 'lodash';
|
|
9
|
+
// Import tooltip komponent pro eliminaci circular dependency
|
|
10
|
+
// import * as Tooltip from '../grid/tooltips';
|
|
9
11
|
/**
|
|
10
12
|
* Hook pro správu grid layout s automatickým ukládáním
|
|
11
13
|
* @param {Object} config - Konfigurace grid layout
|
|
@@ -25,10 +27,12 @@ import { debounce } from 'lodash';
|
|
|
25
27
|
* @returns {Object} Grid layout management interface
|
|
26
28
|
*/
|
|
27
29
|
export const useGridLayout = ({ userKey, applicationName, gridName, filterName, enabled = true, autoSave = true, autoSaveDelay = 2000, columnDefs = [], accessToken, waitForSavedFields = false, // Nový prop pro odložené zobrazení columnDefs
|
|
28
|
-
onLayoutLoaded, onLayoutSaved, onError }) => {
|
|
30
|
+
onLayoutLoaded, onLayoutSaved, onError, }) => {
|
|
29
31
|
// Validace columnDefs - musí být array
|
|
30
|
-
if (columnDefs !== undefined &&
|
|
31
|
-
|
|
32
|
+
if (columnDefs !== undefined &&
|
|
33
|
+
columnDefs !== null &&
|
|
34
|
+
!Array.isArray(columnDefs)) {
|
|
35
|
+
console.error('[GridLayout] columnDefs is not an array:', typeof columnDefs, columnDefs);
|
|
32
36
|
throw new Error('useGridLayout: columnDefs musí být array');
|
|
33
37
|
}
|
|
34
38
|
// Refs pro AG-Grid API
|
|
@@ -36,144 +40,633 @@ onLayoutLoaded, onLayoutSaved, onError }) => {
|
|
|
36
40
|
const columnApiRef = useRef(null);
|
|
37
41
|
// State
|
|
38
42
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
43
|
+
const [isGridReady, setIsGridReady] = useState(false);
|
|
39
44
|
const [isLoading, setIsLoading] = useState(false);
|
|
40
45
|
const [isSaving, setIsSaving] = useState(false);
|
|
46
|
+
const [isApplyingLayout, setIsApplyingLayout] = useState(false);
|
|
41
47
|
const [error, setError] = useState(null);
|
|
42
48
|
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
|
|
43
49
|
const [isColumnEditorOpen, setIsColumnEditorOpen] = useState(false);
|
|
50
|
+
const [lastKnownColumnState, setLastKnownColumnState] = useState(null);
|
|
51
|
+
// Místo version counter použijeme stabilnější mechanismus pro tracking změn
|
|
52
|
+
const [lastColumnDefsHash, setLastColumnDefsHash] = useState('');
|
|
53
|
+
// Utility funkce pro generování hash z columnDefs
|
|
54
|
+
const generateColumnDefsHash = useCallback((colDefs) => {
|
|
55
|
+
if (!Array.isArray(colDefs))
|
|
56
|
+
return '';
|
|
57
|
+
// Vytvoříme hash z klíčových vlastností které ovlivňují rendering
|
|
58
|
+
return colDefs.map(col => `${col.field || col.colId}:${col.width || 'auto'}:${col.hide ? 'hidden' : 'visible'}:${col.headerName || ''}`).join('|');
|
|
59
|
+
}, []);
|
|
44
60
|
// Grid Layout API hook
|
|
45
61
|
const gridLayoutApi = useGridLayoutApi({
|
|
46
62
|
userKey,
|
|
47
63
|
applicationName,
|
|
48
64
|
gridName,
|
|
49
65
|
filterName,
|
|
50
|
-
accessToken
|
|
66
|
+
accessToken,
|
|
51
67
|
});
|
|
52
68
|
// Query pro načtení saved layoutu
|
|
53
|
-
const { data: savedFields, isLoading: isFieldsLoading, error: fieldsError, refetch: refetchFields } = gridLayoutApi.useUserFields((columnDefs || []).map((colDef, index) => ({
|
|
54
|
-
name: colDef.field || `column_${index}`,
|
|
55
|
-
displayName: colDef.headerName ||
|
|
69
|
+
const { data: savedFields, isLoading: isFieldsLoading, error: fieldsError, refetch: refetchFields, } = gridLayoutApi.useUserFields((columnDefs || []).map((colDef, index) => ({
|
|
70
|
+
name: colDef.field || colDef.colId || `column_${index}`,
|
|
71
|
+
displayName: colDef.headerName ||
|
|
72
|
+
colDef.field ||
|
|
73
|
+
colDef.colId ||
|
|
74
|
+
`Column ${index + 1}`,
|
|
56
75
|
dataType: colDef.type || 'string',
|
|
57
76
|
isVisible: !colDef.hide,
|
|
58
77
|
width: colDef.width || 100,
|
|
59
|
-
order: index
|
|
60
|
-
})), {
|
|
78
|
+
order: index,
|
|
79
|
+
})), {
|
|
80
|
+
enabled: enabled &&
|
|
81
|
+
!!userKey &&
|
|
82
|
+
!!gridName &&
|
|
83
|
+
Array.isArray(columnDefs) &&
|
|
84
|
+
columnDefs.length > 0,
|
|
85
|
+
});
|
|
86
|
+
// // Bezpečné aktualizování lastKnownColumnState při otevření editoru
|
|
87
|
+
// useEffect(() => {
|
|
88
|
+
// if (isColumnEditorOpen && columnApiRef.current && typeof columnApiRef.current.getColumnState === 'function') {
|
|
89
|
+
// try {
|
|
90
|
+
// const currentState = columnApiRef.current.getColumnState();
|
|
91
|
+
// if (Array.isArray(currentState) && currentState.length > 0) {
|
|
92
|
+
// // Aktualizujeme lastKnownColumnState po otevření editoru
|
|
93
|
+
// const validColumnDefs = Array.isArray(columnDefs) ? columnDefs : [];
|
|
94
|
+
// const formattedState = currentState.map((columnStateItem, index) => {
|
|
95
|
+
// const colDef = validColumnDefs.find(cd => cd.field === columnStateItem.colId) || {};
|
|
96
|
+
// const savedField = savedFields?.records?.find(sf => sf.fieldName === columnStateItem.colId);
|
|
97
|
+
// return {
|
|
98
|
+
// id: columnStateItem.colId,
|
|
99
|
+
// field: columnStateItem.colId,
|
|
100
|
+
// headerName: savedField?.headerName || colDef.headerName || columnStateItem.colId,
|
|
101
|
+
// originalHeaderName: colDef.headerName || columnStateItem.colId,
|
|
102
|
+
// width: columnStateItem.width || colDef.width || 100,
|
|
103
|
+
// originalWidth: colDef.width || 100,
|
|
104
|
+
// visible: !columnStateItem.hide,
|
|
105
|
+
// order: index
|
|
106
|
+
// };
|
|
107
|
+
// });
|
|
108
|
+
// setLastKnownColumnState(formattedState);
|
|
109
|
+
// console.log('[GridLayout] Updated lastKnownColumnState after opening editor');
|
|
110
|
+
// }
|
|
111
|
+
// } catch (error) {
|
|
112
|
+
// console.error('[GridLayout] Error updating column state after opening editor:', error);
|
|
113
|
+
// }
|
|
114
|
+
// }
|
|
115
|
+
// }, [isColumnEditorOpen, columnDefs, savedFields, columnApiRef]);
|
|
116
|
+
// MutationObserver pro sledování změn v DOM a okamžitou aktualizaci headerName
|
|
117
|
+
// useEffect(() => {
|
|
118
|
+
// if (!savedFields?.records || !isInitialized || !enabled) return;
|
|
119
|
+
// // Reference na observer pro cleanup
|
|
120
|
+
// let observer = null;
|
|
121
|
+
// try {
|
|
122
|
+
// console.log('[GridLayout] Setting up MutationObserver for header changes');
|
|
123
|
+
// // Funkce pro aktualizaci headerName
|
|
124
|
+
// const updateHeaderNames = () => {
|
|
125
|
+
// try {
|
|
126
|
+
// // Vytvoříme mapu fieldName -> headerName z API dat
|
|
127
|
+
// const headerNameMap = new Map();
|
|
128
|
+
// savedFields.records.forEach(field => {
|
|
129
|
+
// if (field.fieldName && field.headerName) {
|
|
130
|
+
// headerNameMap.set(field.fieldName, field.headerName);
|
|
131
|
+
// }
|
|
132
|
+
// });
|
|
133
|
+
// // Najdeme všechny hlavičky sloupců v DOM
|
|
134
|
+
// const headerCells = document.querySelectorAll('.ag-header-cell');
|
|
135
|
+
// // Aktualizujeme texty hlaviček
|
|
136
|
+
// headerCells.forEach(headerCell => {
|
|
137
|
+
// try {
|
|
138
|
+
// // Získáme ID sloupce z DOM atributů
|
|
139
|
+
// const colId = headerCell.getAttribute('col-id');
|
|
140
|
+
// if (colId && headerNameMap.has(colId)) {
|
|
141
|
+
// // Najdeme element s textem hlavičky
|
|
142
|
+
// const headerTextEl = headerCell.querySelector('.ag-header-cell-text');
|
|
143
|
+
// if (headerTextEl) {
|
|
144
|
+
// const newHeaderName = headerNameMap.get(colId);
|
|
145
|
+
// const currentText = headerTextEl.textContent;
|
|
146
|
+
// if (currentText !== newHeaderName) {
|
|
147
|
+
// console.log(`[GridLayout] MutationObserver update: Column '${colId}' header from '${currentText}' to '${newHeaderName}'`);
|
|
148
|
+
// headerTextEl.textContent = newHeaderName;
|
|
149
|
+
// }
|
|
150
|
+
// }
|
|
151
|
+
// }
|
|
152
|
+
// } catch (cellError) {
|
|
153
|
+
// // Tiché selhání - nechceme, aby MutationObserver padal
|
|
154
|
+
// }
|
|
155
|
+
// });
|
|
156
|
+
// } catch (error) {
|
|
157
|
+
// // Tiché selhání - nechceme, aby MutationObserver padal
|
|
158
|
+
// }
|
|
159
|
+
// };
|
|
160
|
+
// // Najdeme element hlavičky
|
|
161
|
+
// const headerElement = document.querySelector('.ag-header');
|
|
162
|
+
// if (headerElement) {
|
|
163
|
+
// // Vytvoříme observer, který bude sledovat změny v hlavičce
|
|
164
|
+
// observer = new MutationObserver((mutations) => {
|
|
165
|
+
// // Detekovali jsme změnu v DOM hlavičky, aktualizujeme headerName
|
|
166
|
+
// updateHeaderNames();
|
|
167
|
+
// });
|
|
168
|
+
// // Začneme sledovat změny v hlavičce
|
|
169
|
+
// observer.observe(headerElement, {
|
|
170
|
+
// childList: true, // sledujeme přidání/odebírání elementů
|
|
171
|
+
// subtree: true, // sledujeme změny i v potomcích
|
|
172
|
+
// characterData: true, // sledujeme změny textu
|
|
173
|
+
// attributeFilter: ['col-id', 'class'] // sledujeme změny těchto atributů
|
|
174
|
+
// });
|
|
175
|
+
// console.log('[GridLayout] MutationObserver set up successfully');
|
|
176
|
+
// } else {
|
|
177
|
+
// console.log('[GridLayout] Header element not found for MutationObserver');
|
|
178
|
+
// }
|
|
179
|
+
// } catch (error) {
|
|
180
|
+
// console.error('[GridLayout] Error setting up MutationObserver:', error);
|
|
181
|
+
// }
|
|
182
|
+
// // Cleanup - odpojit observer při unmount
|
|
183
|
+
// return () => {
|
|
184
|
+
// if (observer) {
|
|
185
|
+
// observer.disconnect();
|
|
186
|
+
// console.log('[GridLayout] MutationObserver disconnected');
|
|
187
|
+
// }
|
|
188
|
+
// };
|
|
189
|
+
// }, [savedFields, isInitialized, enabled]);
|
|
61
190
|
/**
|
|
62
191
|
* Error handler
|
|
63
192
|
*/
|
|
64
193
|
const handleError = useCallback((error, context = '') => {
|
|
65
|
-
console.error
|
|
194
|
+
// Removed console.error for production
|
|
66
195
|
setError(error);
|
|
67
196
|
if (onError) {
|
|
68
197
|
onError(error, context);
|
|
69
198
|
}
|
|
70
199
|
}, [onError]);
|
|
200
|
+
// Stabilní reference pro debouncedSave
|
|
201
|
+
const stableColumnDefsRef = useRef(columnDefs);
|
|
202
|
+
const stableGridLayoutApiRef = useRef(gridLayoutApi);
|
|
203
|
+
const stableOnLayoutSavedRef = useRef(onLayoutSaved);
|
|
204
|
+
const stableHandleErrorRef = useRef(handleError);
|
|
205
|
+
// Reference pro ukládání stavu sloupců bez state update v render cyklu
|
|
206
|
+
const stableCurrentColumnsRef = useRef(null);
|
|
207
|
+
// Aktualizujeme ref hodnoty
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
let updatedColumnDefs = columnDefs;
|
|
210
|
+
// Pro columnDefs zachováváme aktualizované šířky pokud už existují
|
|
211
|
+
if (stableColumnDefsRef.current && Array.isArray(stableColumnDefsRef.current) && Array.isArray(columnDefs)) {
|
|
212
|
+
// Vytvoříme mapu existujících šířek
|
|
213
|
+
const existingWidthsMap = new Map();
|
|
214
|
+
stableColumnDefsRef.current.forEach(colDef => {
|
|
215
|
+
const fieldId = colDef.field || colDef.colId;
|
|
216
|
+
if (fieldId && colDef.width) {
|
|
217
|
+
existingWidthsMap.set(fieldId, colDef.width);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
// Aktualizujeme columnDefs s existujícími šířkami
|
|
221
|
+
updatedColumnDefs = columnDefs.map(colDef => {
|
|
222
|
+
const fieldId = colDef.field || colDef.colId;
|
|
223
|
+
if (fieldId && existingWidthsMap.has(fieldId)) {
|
|
224
|
+
return {
|
|
225
|
+
...colDef,
|
|
226
|
+
width: existingWidthsMap.get(fieldId)
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
return colDef;
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
// Zkontrolujeme zda se columnDefs skutečně změnily pomocí hash
|
|
233
|
+
const newHash = generateColumnDefsHash(updatedColumnDefs);
|
|
234
|
+
if (newHash !== lastColumnDefsHash) {
|
|
235
|
+
stableColumnDefsRef.current = updatedColumnDefs;
|
|
236
|
+
setLastColumnDefsHash(newHash);
|
|
237
|
+
}
|
|
238
|
+
stableGridLayoutApiRef.current = gridLayoutApi;
|
|
239
|
+
stableOnLayoutSavedRef.current = onLayoutSaved;
|
|
240
|
+
stableHandleErrorRef.current = handleError;
|
|
241
|
+
});
|
|
242
|
+
// Efekt pro bezpečnou aktualizaci lastKnownColumnState z ref
|
|
243
|
+
// useEffect(() => {
|
|
244
|
+
// if (stableCurrentColumnsRef.current) {
|
|
245
|
+
// setLastKnownColumnState(stableCurrentColumnsRef.current);
|
|
246
|
+
// console.log('[GridLayout] Updated lastKnownColumnState from ref');
|
|
247
|
+
// // Vymazat po použití
|
|
248
|
+
// stableCurrentColumnsRef.current = null;
|
|
249
|
+
// }
|
|
250
|
+
// }, [stableCurrentColumnsRef.current]);
|
|
71
251
|
/**
|
|
72
252
|
* Uloží současný stav sloupců do API
|
|
73
253
|
*/
|
|
74
254
|
const saveCurrentLayout = useCallback(async () => {
|
|
75
|
-
if (!enabled || !gridApiRef.current
|
|
255
|
+
if (!enabled || !gridApiRef.current) {
|
|
76
256
|
return;
|
|
257
|
+
}
|
|
77
258
|
try {
|
|
78
259
|
setIsSaving(true);
|
|
79
260
|
setError(null);
|
|
80
|
-
// Získáme současný column state z AG-Grid
|
|
81
|
-
|
|
261
|
+
// Získáme současný column state z AG-Grid s fallbackem pro AG Grid v31+
|
|
262
|
+
let columnState = null;
|
|
263
|
+
if (gridApiRef.current &&
|
|
264
|
+
typeof gridApiRef.current.getColumnState === 'function') {
|
|
265
|
+
// AG Grid v31+ - getColumnState je přímo v main API
|
|
266
|
+
try {
|
|
267
|
+
columnState = gridApiRef.current.getColumnState();
|
|
268
|
+
// Získáme aktuální headerName hodnoty z DOM pro každý sloupec
|
|
269
|
+
if (columnState && Array.isArray(columnState)) {
|
|
270
|
+
columnState = columnState.map(colState => {
|
|
271
|
+
// Pokusíme se získat aktuální headerName z DOM
|
|
272
|
+
try {
|
|
273
|
+
const headerCell = document.querySelector(`[col-id="${colState.colId}"]`);
|
|
274
|
+
if (headerCell) {
|
|
275
|
+
const headerTextEl = headerCell.querySelector('.ag-header-cell-text');
|
|
276
|
+
if (headerTextEl && headerTextEl.textContent) {
|
|
277
|
+
return {
|
|
278
|
+
...colState,
|
|
279
|
+
headerName: headerTextEl.textContent
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
catch (headerError) {
|
|
285
|
+
console.log(`[GridLayout] Could not get headerName from DOM for ${colState.colId}`);
|
|
286
|
+
}
|
|
287
|
+
return colState;
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
// Pokud getColumnState vrátí undefined, grid je v nekonzistentním stavu
|
|
291
|
+
// Zkusíme alternativní metodu přes getColumnDefs()
|
|
292
|
+
if (columnState === undefined || columnState === null) {
|
|
293
|
+
console.warn('[GridLayout] getColumnState returned undefined/null, trying getColumnDefs() alternative');
|
|
294
|
+
console.warn('[GridLayout] Full gridApiRef.current object:', gridApiRef.current);
|
|
295
|
+
console.warn('[GridLayout] Available methods on gridApiRef.current:', gridApiRef.current
|
|
296
|
+
? Object.getOwnPropertyNames(gridApiRef.current).filter((name) => typeof gridApiRef.current[name] === 'function')
|
|
297
|
+
: 'NO_GRID_API');
|
|
298
|
+
try {
|
|
299
|
+
// Alternativní přístup: použijeme getColumnDefs() a vytvoříme fake column state
|
|
300
|
+
const columnDefs = gridApiRef.current.getColumnDefs();
|
|
301
|
+
if (columnDefs &&
|
|
302
|
+
Array.isArray(columnDefs) &&
|
|
303
|
+
columnDefs.length > 0) {
|
|
304
|
+
// Vytvoříme column state z column defs
|
|
305
|
+
columnState = columnDefs.map((colDef, index) => {
|
|
306
|
+
// Zkusíme získat aktuální šířku sloupce z DOM
|
|
307
|
+
let currentWidth = colDef.width || 100;
|
|
308
|
+
try {
|
|
309
|
+
const fieldId = colDef.field || colDef.colId;
|
|
310
|
+
const headerElement = document.querySelector(`[col-id="${fieldId}"]`);
|
|
311
|
+
if (headerElement && headerElement.offsetWidth) {
|
|
312
|
+
currentWidth = headerElement.offsetWidth;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
catch (domError) {
|
|
316
|
+
console.log('[GridLayout] Could not get width from DOM for', colDef.field);
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
colId: colDef.field || colDef.colId,
|
|
320
|
+
hide: colDef.hide || false,
|
|
321
|
+
width: currentWidth,
|
|
322
|
+
headerName: colDef.headerName, // Přidáme aktuální headerName
|
|
323
|
+
sort: null, // Nebudeme zachovávat sort při této fallback metodě
|
|
324
|
+
sortIndex: null,
|
|
325
|
+
};
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
console.error('[GridLayout] getColumnDefs() also failed or returned empty array');
|
|
330
|
+
const cachedColumnDefs = stableColumnDefsRef.current;
|
|
331
|
+
if (cachedColumnDefs &&
|
|
332
|
+
Array.isArray(cachedColumnDefs) &&
|
|
333
|
+
cachedColumnDefs.length > 0) {
|
|
334
|
+
columnState = cachedColumnDefs.map((colDef, index) => {
|
|
335
|
+
// Použijeme cached definice
|
|
336
|
+
let currentWidth = colDef.width || 100;
|
|
337
|
+
return {
|
|
338
|
+
colId: colDef.field || colDef.colId,
|
|
339
|
+
hide: colDef.hide || false,
|
|
340
|
+
width: currentWidth,
|
|
341
|
+
headerName: colDef.headerName, // Přidáme aktuální headerName
|
|
342
|
+
sort: null,
|
|
343
|
+
sortIndex: null,
|
|
344
|
+
};
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
console.error('[GridLayout] All fallback methods failed - no column data available');
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
catch (columnDefError) {
|
|
354
|
+
console.error('[GridLayout] getColumnDefs() alternative failed:', columnDefError);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
catch (error) {
|
|
360
|
+
console.error('[GridLayout] Error calling gridApiRef.current.getColumnState():', error);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
else if (columnApiRef.current &&
|
|
365
|
+
typeof columnApiRef.current.getColumnState === 'function') {
|
|
366
|
+
// Starší verze AG Grid - getColumnState je v columnApi
|
|
367
|
+
try {
|
|
368
|
+
columnState = columnApiRef.current.getColumnState();
|
|
369
|
+
// Získáme aktuální headerName hodnoty z DOM pro každý sloupec
|
|
370
|
+
if (columnState && Array.isArray(columnState)) {
|
|
371
|
+
columnState = columnState.map(colState => {
|
|
372
|
+
// Pokusíme se získat aktuální headerName z DOM
|
|
373
|
+
try {
|
|
374
|
+
const headerCell = document.querySelector(`[col-id="${colState.colId}"]`);
|
|
375
|
+
if (headerCell) {
|
|
376
|
+
const headerTextEl = headerCell.querySelector('.ag-header-cell-text');
|
|
377
|
+
if (headerTextEl && headerTextEl.textContent) {
|
|
378
|
+
return {
|
|
379
|
+
...colState,
|
|
380
|
+
headerName: headerTextEl.textContent
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
catch (headerError) {
|
|
386
|
+
console.log(`[GridLayout] Could not get headerName from DOM for ${colState.colId}`);
|
|
387
|
+
}
|
|
388
|
+
return colState;
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
catch (error) {
|
|
393
|
+
console.error('[GridLayout] Error calling columnApiRef.current.getColumnState():', error);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
console.warn('[GridLayout] getColumnState method not available for saving layout');
|
|
399
|
+
console.warn('[GridLayout] Debug info:', {
|
|
400
|
+
gridApiRef: gridApiRef.current,
|
|
401
|
+
columnApiRef: columnApiRef.current,
|
|
402
|
+
gridApiRefKeys: gridApiRef.current
|
|
403
|
+
? Object.keys(gridApiRef.current)
|
|
404
|
+
: 'undefined',
|
|
405
|
+
columnApiRefKeys: columnApiRef.current
|
|
406
|
+
? Object.keys(columnApiRef.current)
|
|
407
|
+
: 'undefined',
|
|
408
|
+
});
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
// Kontrola validity columnDefs a použití fallback pokud je potřeba
|
|
412
|
+
let columnDefsToUse = stableColumnDefsRef.current;
|
|
413
|
+
if (!columnDefsToUse ||
|
|
414
|
+
!Array.isArray(columnDefsToUse) ||
|
|
415
|
+
columnDefsToUse.length === 0) {
|
|
416
|
+
console.warn('[GridLayout] stableColumnDefsRef is empty, using fallback from stableCurrentColumnsRef');
|
|
417
|
+
if (stableCurrentColumnsRef.current &&
|
|
418
|
+
Array.isArray(stableCurrentColumnsRef.current)) {
|
|
419
|
+
// Převedeme cached sloupce zpět na columnDefs format
|
|
420
|
+
columnDefsToUse = stableCurrentColumnsRef.current.map((col) => ({
|
|
421
|
+
field: col.field,
|
|
422
|
+
headerName: col.headerName || col.field,
|
|
423
|
+
width: col.width || 100,
|
|
424
|
+
hide: !col.visible,
|
|
425
|
+
}));
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
console.error('[GridLayout] No valid columnDefs available for saving');
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
82
432
|
// Transformujeme na Grid API format
|
|
83
|
-
const fields =
|
|
433
|
+
const fields = stableGridLayoutApiRef.current.transformColumnStateToFields(columnState, columnDefsToUse);
|
|
84
434
|
// Uložíme do API
|
|
85
|
-
const result =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (
|
|
89
|
-
|
|
435
|
+
const result = stableGridLayoutApiRef.current
|
|
436
|
+
.saveGridLayout(fields)
|
|
437
|
+
.then((result) => {
|
|
438
|
+
if (result.success) {
|
|
439
|
+
setHasUnsavedChanges(false);
|
|
440
|
+
if (stableOnLayoutSavedRef.current) {
|
|
441
|
+
stableOnLayoutSavedRef.current(fields, columnState);
|
|
442
|
+
}
|
|
90
443
|
}
|
|
91
|
-
}
|
|
444
|
+
})
|
|
445
|
+
.catch((error) => {
|
|
446
|
+
stableHandleErrorRef.current(error, 'při ukládání layoutu');
|
|
447
|
+
});
|
|
92
448
|
}
|
|
93
449
|
catch (error) {
|
|
94
|
-
|
|
450
|
+
stableHandleErrorRef.current(error, 'při ukládání layoutu');
|
|
95
451
|
}
|
|
96
452
|
finally {
|
|
97
453
|
setIsSaving(false);
|
|
98
454
|
}
|
|
99
|
-
}, [enabled
|
|
455
|
+
}, [enabled]);
|
|
100
456
|
/**
|
|
101
457
|
* Debounced auto-save pro předcházení častým voláním API
|
|
102
458
|
*/
|
|
103
|
-
const debouncedSave = useMemo(() =>
|
|
459
|
+
const debouncedSave = useMemo(() => {
|
|
460
|
+
const debouncedFn = debounce((...args) => {
|
|
461
|
+
return saveCurrentLayout(...args);
|
|
462
|
+
}, autoSaveDelay);
|
|
463
|
+
return debouncedFn;
|
|
464
|
+
}, [saveCurrentLayout, autoSaveDelay]);
|
|
104
465
|
/**
|
|
105
466
|
* Aplikuje saved layout na AG-Grid
|
|
467
|
+
* @param {boolean} forceApply - Vynucené aplikování ignorující isInitialized stav
|
|
106
468
|
*/
|
|
107
|
-
const applySavedLayout = useCallback(() => {
|
|
108
|
-
|
|
469
|
+
const applySavedLayout = useCallback((forceApply = false) => {
|
|
470
|
+
// Ověříme dostupnost API a inicializaci
|
|
471
|
+
if (!savedFields?.records ||
|
|
472
|
+
savedFields.records.length === 0 ||
|
|
473
|
+
(!forceApply && isInitialized)) {
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
// Ověříme dostupnost applyColumnState metody (AG Grid v31+ má ji v main API)
|
|
477
|
+
let applyColumnStateApi = null;
|
|
478
|
+
if (gridApiRef.current &&
|
|
479
|
+
typeof gridApiRef.current.applyColumnState === 'function') {
|
|
480
|
+
applyColumnStateApi = gridApiRef.current;
|
|
481
|
+
}
|
|
482
|
+
else if (columnApiRef.current &&
|
|
483
|
+
typeof columnApiRef.current.applyColumnState === 'function') {
|
|
484
|
+
applyColumnStateApi = columnApiRef.current;
|
|
485
|
+
}
|
|
486
|
+
if (!applyColumnStateApi) {
|
|
487
|
+
console.warn('[GridLayout] applyColumnState method not available');
|
|
109
488
|
return;
|
|
489
|
+
}
|
|
110
490
|
try {
|
|
111
491
|
setIsLoading(true);
|
|
492
|
+
setIsApplyingLayout(true);
|
|
112
493
|
// Transformujeme Grid API fields na AG-Grid column state
|
|
113
|
-
|
|
114
|
-
|
|
494
|
+
// Použijeme stableColumnDefsRef.current místo columnDefs pro zachování aktuálních šířek
|
|
495
|
+
const columnDefsToUse = stableColumnDefsRef.current || columnDefs;
|
|
496
|
+
const columnState = gridLayoutApi.transformFieldsToColumnState(savedFields.records, columnDefsToUse);
|
|
115
497
|
if (columnState && columnState.length > 0) {
|
|
116
|
-
// Pokud je waitForSavedFields true, columnDefs jsou už pre-transformované,
|
|
498
|
+
// Pokud je waitForSavedFields true, columnDefs jsou už pre-transformované,
|
|
117
499
|
// takže aplikujeme jen width a hide vlastnosti bez delay pro pořadí
|
|
118
500
|
const applyFunction = () => {
|
|
119
501
|
try {
|
|
120
|
-
|
|
121
|
-
columnState,
|
|
122
|
-
columnCount: columnState.length,
|
|
123
|
-
columnIds: columnState.map(c => c.colId),
|
|
124
|
-
hasOrder: true // pořadí je v poli implicitně
|
|
125
|
-
});
|
|
126
|
-
// Debug info o columnApiRef
|
|
127
|
-
console.log("🔍 columnApiRef debug:", {
|
|
128
|
-
hasColumnApiRef: !!columnApiRef.current,
|
|
129
|
-
columnApiType: typeof columnApiRef.current,
|
|
130
|
-
columnApiMethods: columnApiRef.current ? Object.getOwnPropertyNames(columnApiRef.current).filter(name => typeof columnApiRef.current[name] === 'function') : [],
|
|
131
|
-
hasApplyColumnState: columnApiRef.current && typeof columnApiRef.current.applyColumnState === 'function'
|
|
132
|
-
});
|
|
133
|
-
// Ověření, že columnApi podporuje applyColumnState
|
|
134
|
-
if (!columnApiRef.current) {
|
|
135
|
-
throw new Error('columnApiRef.current is null or undefined');
|
|
136
|
-
}
|
|
137
|
-
if (typeof columnApiRef.current.applyColumnState !== 'function') {
|
|
138
|
-
throw new Error(`applyColumnState is not a function. Available methods: ${Object.getOwnPropertyNames(columnApiRef.current).filter(name => typeof columnApiRef.current[name] === 'function').join(', ')}`);
|
|
139
|
-
}
|
|
140
|
-
console.log("test2");
|
|
141
|
-
// Aplikujeme column state na AG-Grid
|
|
502
|
+
// Aplikujeme column state na AG-Grid
|
|
142
503
|
let result;
|
|
143
504
|
try {
|
|
144
505
|
const applyOrderEnabled = !waitForSavedFields; // Při waitForSavedFields už je pořadí v columnDefs
|
|
145
|
-
|
|
146
|
-
|
|
506
|
+
// Při prvotním načtení (isInitialized=false) používáme přímo columnState z API
|
|
507
|
+
// Při následných aplikováních zachováváme aktuální šířky z gridu
|
|
508
|
+
let adjustedColumnState = columnState;
|
|
509
|
+
if (isInitialized) {
|
|
510
|
+
// Pouze pokud už je grid inicializován, zachováváme současné šířky
|
|
511
|
+
const currentColumnState = gridApiRef.current?.getColumnState?.() || [];
|
|
512
|
+
const currentWidthMap = new Map();
|
|
513
|
+
currentColumnState.forEach(colState => {
|
|
514
|
+
if (colState.colId && colState.width) {
|
|
515
|
+
currentWidthMap.set(colState.colId, colState.width);
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
// Upravíme columnState tak, aby zachoval aktuální šířky pokud existují
|
|
519
|
+
adjustedColumnState = columnState.map(colState => {
|
|
520
|
+
const currentWidth = currentWidthMap.get(colState.colId);
|
|
521
|
+
if (currentWidth && currentWidth !== colState.width) {
|
|
522
|
+
return {
|
|
523
|
+
...colState,
|
|
524
|
+
width: currentWidth
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
return colState;
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
result = applyColumnStateApi.applyColumnState({
|
|
531
|
+
state: adjustedColumnState,
|
|
147
532
|
applyOrder: applyOrderEnabled, // Pořadí jen když není waitForSavedFields
|
|
148
533
|
defaultState: {
|
|
149
534
|
sort: null, // Reset sorting na všech sloupcích
|
|
150
|
-
sortIndex: null, // Reset sort index
|
|
535
|
+
sortIndex: null, // Reset sort index
|
|
151
536
|
pivot: null, // Reset pivot
|
|
152
|
-
rowGroup: null // Reset row grouping
|
|
153
|
-
}
|
|
537
|
+
rowGroup: null, // Reset row grouping
|
|
538
|
+
},
|
|
154
539
|
});
|
|
155
|
-
|
|
540
|
+
// Explicitně aktualizujeme headerName pro každý sloupec, protože AG-Grid
|
|
541
|
+
// nepodporuje nastavení headerName přes applyColumnState
|
|
542
|
+
if (savedFields.records &&
|
|
543
|
+
Array.isArray(savedFields.records) &&
|
|
544
|
+
gridApiRef.current) {
|
|
545
|
+
// Nejprve zkusíme použít refreshHeader funkci, pokud je dostupná
|
|
546
|
+
try {
|
|
547
|
+
if (typeof gridApiRef.current.refreshHeader === 'function') {
|
|
548
|
+
gridApiRef.current.refreshHeader();
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
catch (refreshError) {
|
|
552
|
+
console.error('[GridLayout] Error in refreshHeader:', refreshError);
|
|
553
|
+
}
|
|
554
|
+
// Získáme aktuální definice sloupců z gridu
|
|
555
|
+
let currentColDefs;
|
|
556
|
+
try {
|
|
557
|
+
currentColDefs = gridApiRef.current.getColumnDefs
|
|
558
|
+
? gridApiRef.current.getColumnDefs()
|
|
559
|
+
: null;
|
|
560
|
+
}
|
|
561
|
+
catch (error) {
|
|
562
|
+
console.error('[GridLayout] Error getting column definitions:', error);
|
|
563
|
+
currentColDefs = null;
|
|
564
|
+
}
|
|
565
|
+
if (currentColDefs && Array.isArray(currentColDefs)) {
|
|
566
|
+
// Vytvoříme mapu fieldName -> headerName z API dat
|
|
567
|
+
const headerNameMap = new Map();
|
|
568
|
+
savedFields.records.forEach((field) => {
|
|
569
|
+
if (field.fieldName && field.headerName) {
|
|
570
|
+
headerNameMap.set(field.fieldName, field.headerName);
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
// Aktualizujeme headerName pro každý sloupec
|
|
574
|
+
const updatedColDefs = currentColDefs.map((colDef) => {
|
|
575
|
+
const fieldName = colDef.field;
|
|
576
|
+
if (fieldName && headerNameMap.has(fieldName)) {
|
|
577
|
+
const newHeaderName = headerNameMap.get(fieldName);
|
|
578
|
+
// Vytvoříme novou kopii definice sloupce s aktualizovaným headerName
|
|
579
|
+
return {
|
|
580
|
+
...colDef,
|
|
581
|
+
headerName: newHeaderName,
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
return colDef;
|
|
585
|
+
});
|
|
586
|
+
// Aplikujeme aktualizované definice sloupců zpět do gridu
|
|
587
|
+
try {
|
|
588
|
+
if (typeof gridApiRef.current.setColumnDefs === 'function') {
|
|
589
|
+
gridApiRef.current.setColumnDefs(updatedColDefs);
|
|
590
|
+
// Pro jistotu zkontrolujeme, zda byly změny aplikovány
|
|
591
|
+
setTimeout(() => {
|
|
592
|
+
try {
|
|
593
|
+
const afterUpdateColDefs = gridApiRef.current.getColumnDefs();
|
|
594
|
+
// DOM operace dokončeny, můžeme ukončit loading
|
|
595
|
+
setIsApplyingLayout(false);
|
|
596
|
+
}
|
|
597
|
+
catch (checkError) {
|
|
598
|
+
console.error('[GridLayout] Error checking updated columns:', checkError);
|
|
599
|
+
// I při chybě ukončíme loading
|
|
600
|
+
setIsApplyingLayout(false);
|
|
601
|
+
}
|
|
602
|
+
}, 100);
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
// Alternativní řešení - přímá manipulace s DOM
|
|
606
|
+
// Počkáme, až se grid vyrenderuje
|
|
607
|
+
setTimeout(() => {
|
|
608
|
+
try {
|
|
609
|
+
// Vytvoříme mapu pro rychlou identifikaci
|
|
610
|
+
const headerUpdates = new Map();
|
|
611
|
+
updatedColDefs.forEach((colDef) => {
|
|
612
|
+
if (colDef.field && colDef.headerName) {
|
|
613
|
+
headerUpdates.set(colDef.field, colDef.headerName);
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
// Najdeme všechny hlavičky sloupců pomocí DOM
|
|
617
|
+
const headerCells = document.querySelectorAll('.ag-header-cell');
|
|
618
|
+
headerCells.forEach((headerCell) => {
|
|
619
|
+
try {
|
|
620
|
+
// Získáme ID sloupce z DOM atributů
|
|
621
|
+
const colId = headerCell.getAttribute('col-id');
|
|
622
|
+
if (colId && headerUpdates.has(colId)) {
|
|
623
|
+
// Najdeme element s textem hlavičky
|
|
624
|
+
const headerTextEl = headerCell.querySelector('.ag-header-cell-text');
|
|
625
|
+
if (headerTextEl) {
|
|
626
|
+
const newHeaderName = headerUpdates.get(colId);
|
|
627
|
+
const currentText = headerTextEl.textContent;
|
|
628
|
+
headerTextEl.textContent = newHeaderName;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
catch (cellError) {
|
|
633
|
+
console.error('[GridLayout] Error updating header cell:', cellError);
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
// DOM manipulace dokončena, ukončíme loading
|
|
637
|
+
setIsApplyingLayout(false);
|
|
638
|
+
}
|
|
639
|
+
catch (domError) {
|
|
640
|
+
console.error('[GridLayout] Error in DOM manipulation:', domError);
|
|
641
|
+
// I při chybě ukončíme loading
|
|
642
|
+
setIsApplyingLayout(false);
|
|
643
|
+
}
|
|
644
|
+
}, 200);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
catch (setError) {
|
|
648
|
+
console.error('[GridLayout] Error applying column definitions:', setError);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
156
652
|
}
|
|
157
653
|
catch (applyError) {
|
|
158
|
-
console.error("❌ Error during applyColumnState:", applyError);
|
|
159
654
|
throw applyError;
|
|
160
655
|
}
|
|
161
|
-
console.log("✅ Column state applied successfully:", {
|
|
162
|
-
result,
|
|
163
|
-
appliedColumns: columnState.length
|
|
164
|
-
});
|
|
165
|
-
// Ověření, že se sloupce skutečně přeuspořádaly
|
|
166
|
-
const newColumnState = columnApiRef.current.getColumnState();
|
|
167
|
-
console.log("🚀 ~ test3:", newColumnState);
|
|
168
|
-
console.log("🔍 Current column state after apply:", newColumnState.map(c => c.colId));
|
|
169
656
|
if (onLayoutLoaded) {
|
|
170
657
|
onLayoutLoaded(savedFields.records, columnState);
|
|
171
658
|
}
|
|
172
659
|
}
|
|
173
660
|
catch (delayedError) {
|
|
174
|
-
console.error
|
|
661
|
+
// Removed console.error for production
|
|
175
662
|
handleError(delayedError, 'při delayed aplikování layoutu');
|
|
176
663
|
}
|
|
664
|
+
finally {
|
|
665
|
+
// Bezpečnostní ukončení loading pokud se nedokončilo jinde
|
|
666
|
+
setTimeout(() => {
|
|
667
|
+
setIsApplyingLayout(false);
|
|
668
|
+
}, 300);
|
|
669
|
+
}
|
|
177
670
|
};
|
|
178
671
|
// Pro waitForSavedFields aplikujeme okamžitě (pořadí je už v columnDefs)
|
|
179
672
|
// Pro normální režim použijeme delay
|
|
@@ -190,72 +683,327 @@ onLayoutLoaded, onLayoutSaved, onError }) => {
|
|
|
190
683
|
}
|
|
191
684
|
finally {
|
|
192
685
|
setIsInitialized(true);
|
|
686
|
+
setIsGridReady(true); // Obnovíme také isGridReady pro event handlery
|
|
193
687
|
setIsLoading(false);
|
|
688
|
+
// setIsApplyingLayout(false) se nastaví až po dokončení všech DOM operací
|
|
194
689
|
}
|
|
195
|
-
}, [
|
|
690
|
+
}, [
|
|
691
|
+
savedFields,
|
|
692
|
+
gridLayoutApi,
|
|
693
|
+
isInitialized,
|
|
694
|
+
onLayoutLoaded,
|
|
695
|
+
handleError,
|
|
696
|
+
columnDefs,
|
|
697
|
+
waitForSavedFields,
|
|
698
|
+
]);
|
|
699
|
+
/**
|
|
700
|
+
* Odložené akce pro případ rychlé interakce před dokončením inicializace
|
|
701
|
+
*/
|
|
702
|
+
const [pendingActions, setPendingActions] = useState([]);
|
|
703
|
+
// Effect pro zpracování pending actions po dokončení inicializace
|
|
704
|
+
useEffect(() => {
|
|
705
|
+
if (isInitialized && pendingActions.length > 0) {
|
|
706
|
+
// Zpracujeme pending akce s krátkým delay
|
|
707
|
+
setTimeout(() => {
|
|
708
|
+
pendingActions.forEach((action) => {
|
|
709
|
+
switch (action.type) {
|
|
710
|
+
case 'dragStopped':
|
|
711
|
+
if (autoSave && debouncedSave) {
|
|
712
|
+
debouncedSave();
|
|
713
|
+
}
|
|
714
|
+
break;
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
setPendingActions([]);
|
|
718
|
+
}, 100);
|
|
719
|
+
}
|
|
720
|
+
}, [isInitialized, pendingActions, autoSave, debouncedSave]);
|
|
196
721
|
/**
|
|
197
722
|
* Event handlers pro AG-Grid
|
|
198
723
|
*/
|
|
199
724
|
const handleColumnMoved = useCallback(() => {
|
|
200
|
-
if (!enabled || !
|
|
725
|
+
if (!enabled || !isGridReady) {
|
|
201
726
|
return;
|
|
727
|
+
}
|
|
202
728
|
setHasUnsavedChanges(true);
|
|
203
729
|
// Neukládáme při každém pohybu - čekáme na onDragStopped
|
|
204
|
-
}, [enabled,
|
|
730
|
+
}, [enabled, isGridReady]);
|
|
205
731
|
const handleDragStopped = useCallback(() => {
|
|
206
|
-
if (!enabled || !
|
|
732
|
+
if (!enabled || !isGridReady) {
|
|
207
733
|
return;
|
|
734
|
+
}
|
|
208
735
|
setHasUnsavedChanges(true);
|
|
209
|
-
|
|
210
|
-
|
|
736
|
+
// Aktualizujeme šířky sloupců v columnDefs před uložením
|
|
737
|
+
try {
|
|
738
|
+
if (gridApiRef.current && typeof gridApiRef.current.getColumnState === 'function') {
|
|
739
|
+
const currentColumnState = gridApiRef.current.getColumnState();
|
|
740
|
+
if (currentColumnState && Array.isArray(currentColumnState)) {
|
|
741
|
+
// Aktualizujeme šířky v původních columnDefs
|
|
742
|
+
const widthUpdatesMap = new Map();
|
|
743
|
+
currentColumnState.forEach(colState => {
|
|
744
|
+
if (colState.colId && colState.width) {
|
|
745
|
+
widthUpdatesMap.set(colState.colId, colState.width);
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
// Aktualizujeme stableColumnDefsRef s novými šířkami
|
|
749
|
+
if (stableColumnDefsRef.current && Array.isArray(stableColumnDefsRef.current)) {
|
|
750
|
+
const updatedColumnDefs = stableColumnDefsRef.current.map(colDef => {
|
|
751
|
+
const fieldId = colDef.field || colDef.colId;
|
|
752
|
+
if (fieldId && widthUpdatesMap.has(fieldId)) {
|
|
753
|
+
return {
|
|
754
|
+
...colDef,
|
|
755
|
+
width: widthUpdatesMap.get(fieldId)
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
return colDef;
|
|
759
|
+
});
|
|
760
|
+
stableColumnDefsRef.current = updatedColumnDefs;
|
|
761
|
+
// Hash se aktualizuje automaticky v hlavním useEffect
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
catch (error) {
|
|
767
|
+
console.error('[GridLayout] Error updating columnDefs widths in handleDragStopped:', error);
|
|
768
|
+
}
|
|
769
|
+
// Pokud ještě není inicializované, přidáme akci do pending
|
|
770
|
+
if (!isInitialized && autoSave) {
|
|
771
|
+
setPendingActions((prev) => [
|
|
772
|
+
...prev,
|
|
773
|
+
{ type: 'dragStopped', timestamp: Date.now() },
|
|
774
|
+
]);
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
// Normální proces pokud je vše inicializované
|
|
778
|
+
if (autoSave && debouncedSave) {
|
|
211
779
|
debouncedSave();
|
|
212
780
|
}
|
|
213
|
-
|
|
781
|
+
else {
|
|
782
|
+
}
|
|
783
|
+
}, [enabled, isGridReady, isInitialized, autoSave, debouncedSave]);
|
|
214
784
|
const handleColumnResized = useCallback(() => {
|
|
215
|
-
if (!enabled || !
|
|
785
|
+
if (!enabled || !isGridReady)
|
|
216
786
|
return;
|
|
217
787
|
setHasUnsavedChanges(true);
|
|
218
|
-
|
|
788
|
+
// Aktualizujeme šířky sloupců v columnDefs při resize
|
|
789
|
+
try {
|
|
790
|
+
if (gridApiRef.current && typeof gridApiRef.current.getColumnState === 'function') {
|
|
791
|
+
const currentColumnState = gridApiRef.current.getColumnState();
|
|
792
|
+
if (currentColumnState && Array.isArray(currentColumnState)) {
|
|
793
|
+
// Aktualizujeme šířky v původních columnDefs
|
|
794
|
+
const widthUpdatesMap = new Map();
|
|
795
|
+
currentColumnState.forEach(colState => {
|
|
796
|
+
if (colState.colId && colState.width) {
|
|
797
|
+
widthUpdatesMap.set(colState.colId, colState.width);
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
// Aktualizujeme stableColumnDefsRef s novými šířkami
|
|
801
|
+
if (stableColumnDefsRef.current && Array.isArray(stableColumnDefsRef.current)) {
|
|
802
|
+
const updatedColumnDefs = stableColumnDefsRef.current.map(colDef => {
|
|
803
|
+
const fieldId = colDef.field || colDef.colId;
|
|
804
|
+
if (fieldId && widthUpdatesMap.has(fieldId)) {
|
|
805
|
+
return {
|
|
806
|
+
...colDef,
|
|
807
|
+
width: widthUpdatesMap.get(fieldId)
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
return colDef;
|
|
811
|
+
});
|
|
812
|
+
stableColumnDefsRef.current = updatedColumnDefs;
|
|
813
|
+
// Hash se aktualizuje automaticky v hlavním useEffect
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
catch (error) {
|
|
819
|
+
console.error('[GridLayout] Error updating columnDefs widths in handleColumnResized:', error);
|
|
820
|
+
}
|
|
821
|
+
if (autoSave && isInitialized && debouncedSave) {
|
|
219
822
|
debouncedSave();
|
|
220
823
|
}
|
|
221
|
-
}, [enabled, isInitialized, autoSave, debouncedSave]);
|
|
824
|
+
}, [enabled, isGridReady, isInitialized, autoSave, debouncedSave]);
|
|
222
825
|
const handleColumnVisible = useCallback(() => {
|
|
223
|
-
if (!enabled || !
|
|
826
|
+
if (!enabled || !isGridReady)
|
|
224
827
|
return;
|
|
225
828
|
setHasUnsavedChanges(true);
|
|
226
|
-
if (autoSave) {
|
|
829
|
+
if (autoSave && isInitialized && debouncedSave) {
|
|
227
830
|
debouncedSave();
|
|
228
831
|
}
|
|
229
|
-
}, [enabled, isInitialized, autoSave, debouncedSave]);
|
|
832
|
+
}, [enabled, isGridReady, isInitialized, autoSave, debouncedSave]);
|
|
230
833
|
const handleColumnPinned = useCallback(() => {
|
|
231
|
-
if (!enabled || !
|
|
834
|
+
if (!enabled || !isGridReady)
|
|
232
835
|
return;
|
|
233
836
|
setHasUnsavedChanges(true);
|
|
234
|
-
if (autoSave) {
|
|
837
|
+
if (autoSave && isInitialized && debouncedSave) {
|
|
235
838
|
debouncedSave();
|
|
236
839
|
}
|
|
237
|
-
}, [enabled, isInitialized, autoSave, debouncedSave]);
|
|
840
|
+
}, [enabled, isGridReady, isInitialized, autoSave, debouncedSave]);
|
|
238
841
|
/**
|
|
239
842
|
* AG-Grid Ready handler
|
|
240
843
|
*/
|
|
241
844
|
const handleGridReady = useCallback((params) => {
|
|
242
|
-
if (!enabled)
|
|
845
|
+
if (!enabled) {
|
|
243
846
|
return;
|
|
244
|
-
gridApiRef.current = params.api;
|
|
245
|
-
columnApiRef.current = params.columnApi;
|
|
246
|
-
// Pokud už máme saved data, aplikujeme je
|
|
247
|
-
if (savedFields?.records && !isInitialized) {
|
|
248
|
-
applySavedLayout();
|
|
249
847
|
}
|
|
848
|
+
gridApiRef.current = params.api;
|
|
849
|
+
// AG Grid v31+ - columnApi je deprecated, všechny metody jsou v hlavním api
|
|
850
|
+
// Pokud columnApi neexistuje, použijeme main api jako fallback
|
|
851
|
+
columnApiRef.current = params.columnApi || params.api;
|
|
852
|
+
// Okamžitě označíme grid jako připravený pro event handlery
|
|
853
|
+
setIsGridReady(true);
|
|
854
|
+
// POZOR: Nenastavujeme isInitialized zde, protože by to zabránilo aplikování layoutu!
|
|
855
|
+
// isInitialized se nastaví až po aplikování layoutu v applySavedLayout
|
|
250
856
|
}, [enabled, savedFields, isInitialized, applySavedLayout]);
|
|
251
857
|
/**
|
|
252
|
-
* Effect pro aplikování layoutu
|
|
858
|
+
* Effect pro aplikování layoutu při prvotním načtení savedFields
|
|
253
859
|
*/
|
|
254
860
|
useEffect(() => {
|
|
255
|
-
|
|
861
|
+
// Aplikujeme layout pokud:
|
|
862
|
+
// 1. Máme savedFields z API
|
|
863
|
+
// 2. Grid je ready (má API reference)
|
|
864
|
+
// 3. Ještě jsme neinicializovali layout
|
|
865
|
+
if (savedFields?.records && savedFields.records.length > 0 && gridApiRef.current && !isInitialized) {
|
|
256
866
|
applySavedLayout();
|
|
257
867
|
}
|
|
258
|
-
}, [savedFields,
|
|
868
|
+
}, [savedFields?.records, isInitialized, applySavedLayout]);
|
|
869
|
+
/**
|
|
870
|
+
* Původní zakomentovaný effect pro aplikování layoutu když se načtou data
|
|
871
|
+
*/
|
|
872
|
+
// useEffect(() => {
|
|
873
|
+
// if (savedFields?.records && columnApiRef.current && !isInitialized) {
|
|
874
|
+
// console.log('[GridLayout] Layout will be applied from effect');
|
|
875
|
+
// applySavedLayout();
|
|
876
|
+
// } else if (savedFields?.records && columnApiRef.current && isInitialized) {
|
|
877
|
+
// // Pokud je již inicializován, ale přišla nová data, aktualizujeme jen DOM (ne celý layout)
|
|
878
|
+
// console.log('[GridLayout] Already initialized, but received new data - updating headers directly');
|
|
879
|
+
// // Počkáme moment, než se nová data zpracují, a pak aktualizujeme headerName
|
|
880
|
+
// setTimeout(() => {
|
|
881
|
+
// try {
|
|
882
|
+
// // Vytvoříme mapu fieldName -> headerName z API dat
|
|
883
|
+
// const headerNameMap = new Map();
|
|
884
|
+
// savedFields.records.forEach(field => {
|
|
885
|
+
// if (field.fieldName && field.headerName) {
|
|
886
|
+
// headerNameMap.set(field.fieldName, field.headerName);
|
|
887
|
+
// console.log(`[GridLayout] Update after reload: '${field.fieldName}' -> '${field.headerName}'`);
|
|
888
|
+
// }
|
|
889
|
+
// });
|
|
890
|
+
// // Najdeme všechny hlavičky sloupců v DOM
|
|
891
|
+
// const headerCells = document.querySelectorAll('.ag-header-cell');
|
|
892
|
+
// console.log('[GridLayout] Found header cells after reload:', headerCells.length);
|
|
893
|
+
// // Aktualizujeme texty hlaviček
|
|
894
|
+
// headerCells.forEach(headerCell => {
|
|
895
|
+
// try {
|
|
896
|
+
// // Získáme ID sloupce z DOM atributů
|
|
897
|
+
// const colId = headerCell.getAttribute('col-id');
|
|
898
|
+
// if (colId && headerNameMap.has(colId)) {
|
|
899
|
+
// // Najdeme element s textem hlavičky
|
|
900
|
+
// const headerTextEl = headerCell.querySelector('.ag-header-cell-text');
|
|
901
|
+
// if (headerTextEl) {
|
|
902
|
+
// const newHeaderName = headerNameMap.get(colId);
|
|
903
|
+
// const currentText = headerTextEl.textContent;
|
|
904
|
+
// console.log(`[GridLayout] DOM update after reload: Column '${colId}' header from '${currentText}' to '${newHeaderName}'`);
|
|
905
|
+
// headerTextEl.textContent = newHeaderName;
|
|
906
|
+
// }
|
|
907
|
+
// }
|
|
908
|
+
// } catch (cellError) {
|
|
909
|
+
// console.error('[GridLayout] Error updating header cell after reload:', cellError);
|
|
910
|
+
// }
|
|
911
|
+
// });
|
|
912
|
+
// // Zkusíme vynutit překreslení hlavičky
|
|
913
|
+
// if (typeof gridApiRef.current.refreshHeader === 'function') {
|
|
914
|
+
// console.log('[GridLayout] Forcing header refresh after reload');
|
|
915
|
+
// gridApiRef.current.refreshHeader();
|
|
916
|
+
// }
|
|
917
|
+
// } catch (error) {
|
|
918
|
+
// console.error('[GridLayout] Error updating headers after reload:', error);
|
|
919
|
+
// }
|
|
920
|
+
// }, 200);
|
|
921
|
+
// }
|
|
922
|
+
// }, [savedFields, applySavedLayout, isInitialized, columnApiRef]);
|
|
923
|
+
/**
|
|
924
|
+
* Alternativní metoda pro aktualizaci headerName po inicializaci gridu
|
|
925
|
+
*/
|
|
926
|
+
// useEffect(() => {
|
|
927
|
+
// // Pokud již proběhla inicializace a máme uložená data z API
|
|
928
|
+
// if (isInitialized && savedFields?.records && gridApiRef.current) {
|
|
929
|
+
// console.log('[GridLayout] Attempting alternative header update after initialization');
|
|
930
|
+
// // Zkusíme použít metodu columnDefHeaderNameChanged, pokud je dostupná
|
|
931
|
+
// try {
|
|
932
|
+
// if (typeof gridApiRef.current.columnDefHeaderNameChanged === 'function') {
|
|
933
|
+
// console.log('[GridLayout] Trying columnDefHeaderNameChanged method');
|
|
934
|
+
// // Vytvoříme mapu fieldName -> headerName z API dat
|
|
935
|
+
// const headerNameMap = new Map();
|
|
936
|
+
// savedFields.records.forEach(field => {
|
|
937
|
+
// if (field.fieldName && field.headerName) {
|
|
938
|
+
// headerNameMap.set(field.fieldName, field.headerName);
|
|
939
|
+
// }
|
|
940
|
+
// });
|
|
941
|
+
// // Získáme aktuální definice sloupců
|
|
942
|
+
// const currentColumnDefs = gridApiRef.current.getColumnDefs();
|
|
943
|
+
// if (currentColumnDefs && Array.isArray(currentColumnDefs)) {
|
|
944
|
+
// currentColumnDefs.forEach(colDef => {
|
|
945
|
+
// if (colDef.field && headerNameMap.has(colDef.field)) {
|
|
946
|
+
// const newHeaderName = headerNameMap.get(colDef.field);
|
|
947
|
+
// if (colDef.headerName !== newHeaderName) {
|
|
948
|
+
// console.log(`[GridLayout] Using columnDefHeaderNameChanged for '${colDef.field}': '${colDef.headerName}' -> '${newHeaderName}'`);
|
|
949
|
+
// colDef.headerName = newHeaderName;
|
|
950
|
+
// gridApiRef.current.columnDefHeaderNameChanged(colDef);
|
|
951
|
+
// }
|
|
952
|
+
// }
|
|
953
|
+
// });
|
|
954
|
+
// }
|
|
955
|
+
// }
|
|
956
|
+
// } catch (error) {
|
|
957
|
+
// console.error('[GridLayout] Error using columnDefHeaderNameChanged:', error);
|
|
958
|
+
// }
|
|
959
|
+
// // Počkáme chvíli, aby se grid stihl plně vyrenderovat
|
|
960
|
+
// setTimeout(() => {
|
|
961
|
+
// try {
|
|
962
|
+
// // Získáme aktuální definice sloupců z gridu
|
|
963
|
+
// const currentColDefs = gridApiRef.current.getColumnDefs ? gridApiRef.current.getColumnDefs() : null;
|
|
964
|
+
// if (currentColDefs && Array.isArray(currentColDefs)) {
|
|
965
|
+
// // Vytvoříme mapu fieldName -> headerName z API dat
|
|
966
|
+
// const headerNameMap = new Map();
|
|
967
|
+
// savedFields.records.forEach(field => {
|
|
968
|
+
// if (field.fieldName && field.headerName) {
|
|
969
|
+
// headerNameMap.set(field.fieldName, field.headerName);
|
|
970
|
+
// }
|
|
971
|
+
// });
|
|
972
|
+
// // Zkontrolujeme, zda je třeba aktualizovat nějaké headery
|
|
973
|
+
// let needsUpdate = false;
|
|
974
|
+
// const updatedColDefs = currentColDefs.map(colDef => {
|
|
975
|
+
// const fieldName = colDef.field;
|
|
976
|
+
// if (fieldName && headerNameMap.has(fieldName)) {
|
|
977
|
+
// const newHeaderName = headerNameMap.get(fieldName);
|
|
978
|
+
// if (colDef.headerName !== newHeaderName) {
|
|
979
|
+
// needsUpdate = true;
|
|
980
|
+
// console.log(`[GridLayout] Alternative update: Column '${fieldName}' header from '${colDef.headerName}' to '${newHeaderName}'`);
|
|
981
|
+
// return {
|
|
982
|
+
// ...colDef,
|
|
983
|
+
// headerName: newHeaderName
|
|
984
|
+
// };
|
|
985
|
+
// }
|
|
986
|
+
// }
|
|
987
|
+
// return colDef;
|
|
988
|
+
// });
|
|
989
|
+
// if (needsUpdate && typeof gridApiRef.current.setColumnDefs === 'function') {
|
|
990
|
+
// console.log('[GridLayout] Applying alternative column header update');
|
|
991
|
+
// gridApiRef.current.setColumnDefs(updatedColDefs);
|
|
992
|
+
// // Zkusíme vynutit překreslení hlavičky
|
|
993
|
+
// setTimeout(() => {
|
|
994
|
+
// if (typeof gridApiRef.current.refreshHeader === 'function') {
|
|
995
|
+
// console.log('[GridLayout] Forcing header refresh');
|
|
996
|
+
// gridApiRef.current.refreshHeader();
|
|
997
|
+
// }
|
|
998
|
+
// }, 50);
|
|
999
|
+
// }
|
|
1000
|
+
// }
|
|
1001
|
+
// } catch (error) {
|
|
1002
|
+
// console.error('[GridLayout] Error in alternative header update:', error);
|
|
1003
|
+
// }
|
|
1004
|
+
// }, 300);
|
|
1005
|
+
// }
|
|
1006
|
+
// }, [isInitialized, savedFields, gridApiRef]);
|
|
259
1007
|
/**
|
|
260
1008
|
* Effect pro error handling
|
|
261
1009
|
*/
|
|
@@ -276,12 +1024,26 @@ onLayoutLoaded, onLayoutSaved, onError }) => {
|
|
|
276
1024
|
* Resetuje layout na default
|
|
277
1025
|
*/
|
|
278
1026
|
const resetToDefault = useCallback(async () => {
|
|
279
|
-
if (!enabled
|
|
1027
|
+
if (!enabled)
|
|
280
1028
|
return;
|
|
1029
|
+
// Ověříme dostupnost resetColumnState metody (AG Grid v31+ má ji v main API)
|
|
1030
|
+
let resetColumnStateApi = null;
|
|
1031
|
+
if (gridApiRef.current &&
|
|
1032
|
+
typeof gridApiRef.current.resetColumnState === 'function') {
|
|
1033
|
+
resetColumnStateApi = gridApiRef.current;
|
|
1034
|
+
}
|
|
1035
|
+
else if (columnApiRef.current &&
|
|
1036
|
+
typeof columnApiRef.current.resetColumnState === 'function') {
|
|
1037
|
+
resetColumnStateApi = columnApiRef.current;
|
|
1038
|
+
}
|
|
1039
|
+
else {
|
|
1040
|
+
console.warn('[GridLayout] resetColumnState method not available');
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
281
1043
|
try {
|
|
282
1044
|
setIsLoading(true);
|
|
283
1045
|
// Resetujeme AG-Grid na původní column definitions
|
|
284
|
-
|
|
1046
|
+
resetColumnStateApi.resetColumnState();
|
|
285
1047
|
// Pokud je autoSave zapnuté, uložíme resetovaný stav
|
|
286
1048
|
if (autoSave) {
|
|
287
1049
|
await saveCurrentLayout();
|
|
@@ -308,8 +1070,22 @@ onLayoutLoaded, onLayoutSaved, onError }) => {
|
|
|
308
1070
|
*/
|
|
309
1071
|
const reloadLayout = useCallback(async () => {
|
|
310
1072
|
try {
|
|
1073
|
+
// Save a reference to the current grid API before resetting states
|
|
1074
|
+
const savedGridApiRef = gridApiRef.current;
|
|
1075
|
+
const savedColumnApiRef = columnApiRef.current;
|
|
311
1076
|
setIsInitialized(false);
|
|
1077
|
+
setIsGridReady(false);
|
|
312
1078
|
await refetchFields();
|
|
1079
|
+
// Restore saved references if they were lost during the reload process
|
|
1080
|
+
if (!gridApiRef.current && savedGridApiRef) {
|
|
1081
|
+
gridApiRef.current = savedGridApiRef;
|
|
1082
|
+
}
|
|
1083
|
+
if (!columnApiRef.current && savedColumnApiRef) {
|
|
1084
|
+
columnApiRef.current = savedColumnApiRef;
|
|
1085
|
+
}
|
|
1086
|
+
// Po refetch dat obnovíme oba stavy (layout je už v DB)
|
|
1087
|
+
setIsInitialized(true);
|
|
1088
|
+
setIsGridReady(true);
|
|
313
1089
|
}
|
|
314
1090
|
catch (error) {
|
|
315
1091
|
handleError(error, 'při reload layoutu');
|
|
@@ -319,83 +1095,102 @@ onLayoutLoaded, onLayoutSaved, onError }) => {
|
|
|
319
1095
|
* Získá aktuální column state pro Column Editor
|
|
320
1096
|
*/
|
|
321
1097
|
const getCurrentColumnsForEditor = useCallback(() => {
|
|
322
|
-
console.log("🔍 getCurrentColumnsForEditor called", {
|
|
323
|
-
hasColumnApiRef: !!columnApiRef.current,
|
|
324
|
-
columnDefs: columnDefs?.length || 0,
|
|
325
|
-
savedFieldsCount: savedFields?.records?.length || 0
|
|
326
|
-
});
|
|
327
1098
|
// Zajistíme, že máme validní columnDefs
|
|
328
1099
|
const validColumnDefs = Array.isArray(columnDefs) ? columnDefs : [];
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
1100
|
+
try {
|
|
1101
|
+
let currentColumnState = null;
|
|
1102
|
+
// Pokusíme se získat column state s různými fallbacky pro AG Grid v31+
|
|
1103
|
+
if (gridApiRef.current &&
|
|
1104
|
+
typeof gridApiRef.current.getColumnState === 'function') {
|
|
1105
|
+
// AG Grid v31+ - getColumnState je přímo v main API
|
|
1106
|
+
currentColumnState = gridApiRef.current.getColumnState();
|
|
1107
|
+
}
|
|
1108
|
+
else if (columnApiRef.current &&
|
|
1109
|
+
typeof columnApiRef.current.getColumnState === 'function') {
|
|
1110
|
+
// Starší verze AG Grid - getColumnState je v columnApi
|
|
1111
|
+
currentColumnState = columnApiRef.current.getColumnState();
|
|
1112
|
+
}
|
|
1113
|
+
else {
|
|
1114
|
+
throw new Error('getColumnState method is not available on gridApiRef or columnApiRef');
|
|
1115
|
+
}
|
|
1116
|
+
if (!Array.isArray(currentColumnState) ||
|
|
1117
|
+
currentColumnState.length === 0) {
|
|
1118
|
+
// Fallback pokud getColumnState() nevrátí validní array
|
|
1119
|
+
if (lastKnownColumnState) {
|
|
1120
|
+
return lastKnownColumnState;
|
|
1121
|
+
}
|
|
1122
|
+
const defaultColumns = validColumnDefs.map((col, index) => ({
|
|
1123
|
+
id: col.field,
|
|
1124
|
+
field: col.field,
|
|
1125
|
+
headerName: col.headerName || col.field,
|
|
1126
|
+
originalHeaderName: col.headerName || col.field,
|
|
1127
|
+
width: col.width || 100,
|
|
1128
|
+
originalWidth: col.width || 100,
|
|
1129
|
+
visible: !col.hide,
|
|
1130
|
+
order: index,
|
|
1131
|
+
originalOrder: index, // Původní pořadí z columnDefs
|
|
1132
|
+
}));
|
|
1133
|
+
// POZN: Neukládáme do state, aby nedocházelo k infinite loop
|
|
1134
|
+
return defaultColumns;
|
|
1135
|
+
}
|
|
1136
|
+
const result = currentColumnState.map((columnStateItem, index) => {
|
|
1137
|
+
// Najdeme odpovídající column definition podle colId (zohledníme field i colId)
|
|
1138
|
+
const colDef = validColumnDefs.find((cd) => cd.field === columnStateItem.colId ||
|
|
1139
|
+
cd.colId === columnStateItem.colId) || {};
|
|
1140
|
+
// Pokusíme se najít saved hodnotu pro headerName
|
|
1141
|
+
const savedField = savedFields?.records?.find((sf) => sf.fieldName === columnStateItem.colId);
|
|
1142
|
+
// Najdeme původní index z columnDefs
|
|
1143
|
+
const originalIndex = validColumnDefs.findIndex((cd) => (cd.field || cd.colId) === columnStateItem.colId);
|
|
1144
|
+
return {
|
|
1145
|
+
id: columnStateItem.colId,
|
|
1146
|
+
field: columnStateItem.colId,
|
|
1147
|
+
headerName: savedField?.headerName ||
|
|
1148
|
+
colDef.headerName ||
|
|
1149
|
+
columnStateItem.colId,
|
|
1150
|
+
// Původní headerName z columnDefs (ne z uložených uživatelských preferencí)
|
|
1151
|
+
originalHeaderName: colDef.headerName || columnStateItem.colId,
|
|
1152
|
+
width: columnStateItem.width || colDef.width || 100,
|
|
1153
|
+
originalWidth: colDef.width || 100,
|
|
1154
|
+
visible: !columnStateItem.hide,
|
|
1155
|
+
order: index,
|
|
1156
|
+
originalOrder: originalIndex !== -1 ? originalIndex : index, // Původní pořadí z columnDefs
|
|
1157
|
+
};
|
|
1158
|
+
});
|
|
1159
|
+
// POZN: Neukládáme do state, aby nedocházelo k infinite loop
|
|
1160
|
+
// Tato aktualizace proběhne v useEffect
|
|
1161
|
+
return result;
|
|
342
1162
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
headerName: col.headerName || col.field,
|
|
357
|
-
originalHeaderName: col.headerName || col.field,
|
|
1163
|
+
catch (error) {
|
|
1164
|
+
console.error('[GridLayout] Error in getCurrentColumnsForEditor:', error);
|
|
1165
|
+
// Použijeme lastKnownColumnState, pokud existuje
|
|
1166
|
+
if (lastKnownColumnState) {
|
|
1167
|
+
return lastKnownColumnState;
|
|
1168
|
+
}
|
|
1169
|
+
// Poslední fallback na columnDefs
|
|
1170
|
+
const defaultColumns = validColumnDefs.map((col, index) => ({
|
|
1171
|
+
id: col.field || col.colId,
|
|
1172
|
+
field: col.field || col.colId,
|
|
1173
|
+
headerName: col.headerName || col.field || col.colId,
|
|
1174
|
+
// Vždy používáme původní definici jako referenci pro porovnání
|
|
1175
|
+
originalHeaderName: col.headerName || col.field || col.colId,
|
|
358
1176
|
width: col.width || 100,
|
|
359
1177
|
originalWidth: col.width || 100,
|
|
360
1178
|
visible: !col.hide,
|
|
361
|
-
order: index
|
|
1179
|
+
order: index,
|
|
1180
|
+
originalOrder: index, // Původní pořadí z columnDefs
|
|
362
1181
|
}));
|
|
1182
|
+
// POZN: Neukládáme do state, aby nedocházelo k infinite loop
|
|
1183
|
+
return defaultColumns;
|
|
363
1184
|
}
|
|
364
|
-
|
|
365
|
-
// Najdeme odpovídající column definition podle colId
|
|
366
|
-
const colDef = validColumnDefs.find(cd => cd.field === columnStateItem.colId) || {};
|
|
367
|
-
// Pokusíme se najít saved hodnotu pro headerName
|
|
368
|
-
const savedField = savedFields?.records?.find(sf => sf.fieldName === columnStateItem.colId);
|
|
369
|
-
return {
|
|
370
|
-
id: columnStateItem.colId,
|
|
371
|
-
field: columnStateItem.colId,
|
|
372
|
-
headerName: savedField?.headerName || colDef.headerName || columnStateItem.colId,
|
|
373
|
-
originalHeaderName: colDef.headerName || columnStateItem.colId,
|
|
374
|
-
width: columnStateItem.width || colDef.width || 100,
|
|
375
|
-
originalWidth: colDef.width || 100,
|
|
376
|
-
visible: !columnStateItem.hide,
|
|
377
|
-
order: index
|
|
378
|
-
};
|
|
379
|
-
});
|
|
380
|
-
console.log("✅ Using AG-Grid state - result:", result.map(r => ({
|
|
381
|
-
field: r.field,
|
|
382
|
-
headerName: r.headerName,
|
|
383
|
-
width: r.width,
|
|
384
|
-
visible: r.visible
|
|
385
|
-
})));
|
|
386
|
-
return result;
|
|
387
|
-
}, [columnDefs, savedFields]);
|
|
1185
|
+
}, [columnDefs, savedFields, lastKnownColumnState]);
|
|
388
1186
|
/**
|
|
389
1187
|
* Otevře Column Editor modal
|
|
390
1188
|
*/
|
|
391
1189
|
const openColumnEditor = useCallback(() => {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
isInitialized,
|
|
395
|
-
columnDefsCount: columnDefs?.length || 0
|
|
396
|
-
});
|
|
1190
|
+
// Před otevřením editoru si pouze zaznamenáme, že chceme aktualizovat stav sloupců
|
|
1191
|
+
// Samotná aktualizace proběhne v useEffect, ne během renderu
|
|
397
1192
|
setIsColumnEditorOpen(true);
|
|
398
|
-
}, [
|
|
1193
|
+
}, []);
|
|
399
1194
|
/**
|
|
400
1195
|
* Zavře Column Editor modal
|
|
401
1196
|
*/
|
|
@@ -406,72 +1201,126 @@ onLayoutLoaded, onLayoutSaved, onError }) => {
|
|
|
406
1201
|
* Uloží změny z Column Editoru
|
|
407
1202
|
* @param {Array} editedColumns - Editované sloupce z modalu
|
|
408
1203
|
*/
|
|
409
|
-
const saveColumnEditorChanges =
|
|
410
|
-
|
|
411
|
-
if (!enabled || !columnApiRef.current)
|
|
1204
|
+
const saveColumnEditorChanges = async (editedColumns) => {
|
|
1205
|
+
if (!enabled)
|
|
412
1206
|
return;
|
|
413
1207
|
try {
|
|
414
1208
|
setIsLoading(true);
|
|
1209
|
+
setIsSaving(true);
|
|
415
1210
|
// Filtrujeme pouze validní sloupce (s definovaným field)
|
|
416
|
-
const validColumns = editedColumns.filter(col => col.field && col.field !== undefined);
|
|
417
|
-
//
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
sortIndex: null
|
|
425
|
-
}));
|
|
426
|
-
// Aplikujeme změny na AG-Grid
|
|
427
|
-
columnApiRef.current.applyColumnState({
|
|
428
|
-
state: columnState,
|
|
429
|
-
applyOrder: true,
|
|
430
|
-
defaultState: {
|
|
431
|
-
sort: null,
|
|
432
|
-
sortIndex: null,
|
|
433
|
-
pivot: null,
|
|
434
|
-
rowGroup: null
|
|
435
|
-
}
|
|
436
|
-
});
|
|
437
|
-
// Připravíme UserFields pro save podle C# SaveUserFieldModel struktury
|
|
438
|
-
const userFields = validColumns.map((col, index) => ({
|
|
1211
|
+
const validColumns = editedColumns.filter((col) => col.field && col.field !== undefined);
|
|
1212
|
+
// Připravíme UserFields pro API podle C# SaveUserFieldModel struktury
|
|
1213
|
+
const completeUserFields = validColumns.map((col, index) => ({
|
|
1214
|
+
Id: 0, // Nové pole má ID = 0, existující budou mít správné ID z API
|
|
1215
|
+
UserKey: userKey,
|
|
1216
|
+
ApplicationName: applicationName,
|
|
1217
|
+
GridName: gridName,
|
|
1218
|
+
FilterName: filterName || null,
|
|
439
1219
|
FieldName: col.field,
|
|
440
|
-
HeaderName: col.headerName || col.field,
|
|
1220
|
+
HeaderName: col.headerName || col.field,
|
|
441
1221
|
Order: index, // Pořadí podle pozice v editedColumns
|
|
442
1222
|
Show: col.visible,
|
|
443
|
-
Width: col.width
|
|
1223
|
+
Width: col.width != null ? col.width : null, // Zachováváme i nulovou šířku
|
|
1224
|
+
System: false,
|
|
444
1225
|
}));
|
|
445
|
-
//
|
|
446
|
-
|
|
447
|
-
|
|
1226
|
+
// Uložení do API
|
|
1227
|
+
gridLayoutApi
|
|
1228
|
+
.saveGridLayout(completeUserFields)
|
|
1229
|
+
.then((result) => {
|
|
448
1230
|
if (result.success) {
|
|
449
1231
|
setHasUnsavedChanges(false);
|
|
450
|
-
//
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
1232
|
+
// Znovunačtení layoutu z API a aplikování na grid
|
|
1233
|
+
reloadLayout().then(async () => {
|
|
1234
|
+
// Po reloadLayout() počkáme na aktualizaci savedFields a aplikujeme layout
|
|
1235
|
+
try {
|
|
1236
|
+
// Znovu načteme fieldy pro zajištění synchronizace
|
|
1237
|
+
const freshFields = await refetchFields();
|
|
1238
|
+
setTimeout(() => {
|
|
1239
|
+
if (gridApiRef.current && freshFields?.data?.records) {
|
|
1240
|
+
// Aplikujeme layout s novými daty
|
|
1241
|
+
const columnState = gridLayoutApi.transformFieldsToColumnState(freshFields.data.records, columnDefs);
|
|
1242
|
+
if (columnState && columnState.length > 0) {
|
|
1243
|
+
// Najdeme správné API pro applyColumnState
|
|
1244
|
+
let applyColumnStateApi = null;
|
|
1245
|
+
if (gridApiRef.current?.applyColumnState) {
|
|
1246
|
+
applyColumnStateApi = gridApiRef.current;
|
|
1247
|
+
}
|
|
1248
|
+
else if (columnApiRef.current?.applyColumnState) {
|
|
1249
|
+
applyColumnStateApi = columnApiRef.current;
|
|
1250
|
+
}
|
|
1251
|
+
if (applyColumnStateApi) {
|
|
1252
|
+
applyColumnStateApi.applyColumnState({
|
|
1253
|
+
state: columnState,
|
|
1254
|
+
applyOrder: true,
|
|
1255
|
+
defaultState: {
|
|
1256
|
+
sort: null,
|
|
1257
|
+
sortIndex: null,
|
|
1258
|
+
pivot: null,
|
|
1259
|
+
rowGroup: null,
|
|
1260
|
+
},
|
|
1261
|
+
});
|
|
1262
|
+
// Aktualizujeme headerName pro každý sloupec
|
|
1263
|
+
const headerNameMap = new Map();
|
|
1264
|
+
freshFields.data.records.forEach((field) => {
|
|
1265
|
+
if (field.fieldName && field.headerName) {
|
|
1266
|
+
headerNameMap.set(field.fieldName, field.headerName);
|
|
1267
|
+
}
|
|
1268
|
+
});
|
|
1269
|
+
// Aplikujeme nové headerName hodnoty přes DOM
|
|
1270
|
+
setTimeout(() => {
|
|
1271
|
+
try {
|
|
1272
|
+
const headerCells = document.querySelectorAll('.ag-header-cell');
|
|
1273
|
+
headerCells.forEach((headerCell) => {
|
|
1274
|
+
const colId = headerCell.getAttribute('col-id');
|
|
1275
|
+
if (colId && headerNameMap.has(colId)) {
|
|
1276
|
+
const headerTextEl = headerCell.querySelector('.ag-header-cell-text');
|
|
1277
|
+
if (headerTextEl) {
|
|
1278
|
+
headerTextEl.textContent = headerNameMap.get(colId);
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
// Vynutíme refresh hlavičky
|
|
1283
|
+
if (gridApiRef.current?.refreshHeader) {
|
|
1284
|
+
gridApiRef.current.refreshHeader();
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
catch (headerError) {
|
|
1288
|
+
console.error('[GridLayout] Error updating headers:', headerError);
|
|
1289
|
+
}
|
|
1290
|
+
}, 50);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
}, 150);
|
|
1295
|
+
}
|
|
1296
|
+
catch (refreshError) {
|
|
1297
|
+
console.error('[GridLayout] Error in post-save refresh:', refreshError);
|
|
1298
|
+
// Fallback na standardní applySavedLayout
|
|
1299
|
+
setTimeout(() => {
|
|
1300
|
+
if (gridApiRef.current) {
|
|
1301
|
+
applySavedLayout(true);
|
|
1302
|
+
}
|
|
1303
|
+
}, 200);
|
|
1304
|
+
}
|
|
1305
|
+
});
|
|
458
1306
|
if (onLayoutSaved) {
|
|
459
|
-
onLayoutSaved(
|
|
1307
|
+
onLayoutSaved(completeUserFields);
|
|
460
1308
|
}
|
|
461
1309
|
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
}
|
|
466
|
-
console.log("✅ Column Editor changes applied successfully");
|
|
1310
|
+
})
|
|
1311
|
+
.catch((error) => {
|
|
1312
|
+
handleError(error, 'při ukládání změn z Column Editoru');
|
|
1313
|
+
});
|
|
467
1314
|
}
|
|
468
1315
|
catch (error) {
|
|
469
|
-
handleError(error, 'při
|
|
1316
|
+
handleError(error, 'při ukládání změn z Column Editoru');
|
|
470
1317
|
}
|
|
471
1318
|
finally {
|
|
472
1319
|
setIsLoading(false);
|
|
1320
|
+
setIsSaving(false);
|
|
473
1321
|
}
|
|
474
|
-
}
|
|
1322
|
+
};
|
|
1323
|
+
//, [enabled, gridLayoutApi, onLayoutSaved, handleError, userKey, applicationName, gridName, filterName, reloadLayout]);
|
|
475
1324
|
// Logika pro zobrazení columnDefs
|
|
476
1325
|
const shouldShowColumns = useMemo(() => {
|
|
477
1326
|
if (!waitForSavedFields)
|
|
@@ -480,42 +1329,149 @@ onLayoutLoaded, onLayoutSaved, onError }) => {
|
|
|
480
1329
|
return !isFieldsLoading && !isLoading;
|
|
481
1330
|
}, [waitForSavedFields, isFieldsLoading, isLoading]);
|
|
482
1331
|
// Pre-transformované columnDefs podle savedFields pro waitForSavedFields mode
|
|
1332
|
+
// DŮLEŽITÉ: Toto useMemo nyní obsahuje i AgGridColumns transformaci pro eliminaci circular dependency
|
|
483
1333
|
const preTransformedColumnDefs = useMemo(() => {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
//
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
1334
|
+
// Použijeme aktualizované columnDefs ze stableColumnDefsRef pokud existují
|
|
1335
|
+
const columnDefsToUse = stableColumnDefsRef.current || columnDefs;
|
|
1336
|
+
let baseColumnDefs = columnDefsToUse;
|
|
1337
|
+
// Pro waitForSavedFields aplikujeme grid layout transformace
|
|
1338
|
+
if (waitForSavedFields &&
|
|
1339
|
+
savedFields?.records &&
|
|
1340
|
+
Array.isArray(columnDefsToUse)) {
|
|
1341
|
+
// Transformujeme columnDefs podle savedFields PŘED zobrazením gridu
|
|
1342
|
+
const columnState = gridLayoutApi.transformFieldsToColumnState(savedFields.records, columnDefsToUse);
|
|
1343
|
+
if (columnState && columnState.length > 0) {
|
|
1344
|
+
// Vytvoříme mapu pro rychlé vyhledávání
|
|
1345
|
+
const columnStateMap = new Map();
|
|
1346
|
+
columnState.forEach((colState, index) => {
|
|
1347
|
+
columnStateMap.set(colState.colId, { ...colState, __order: index });
|
|
1348
|
+
});
|
|
1349
|
+
// Vytvoříme mapu fieldName -> headerName z API dat
|
|
1350
|
+
const headerNameMap = new Map();
|
|
1351
|
+
savedFields.records.forEach((field) => {
|
|
1352
|
+
if (field.fieldName && field.headerName) {
|
|
1353
|
+
headerNameMap.set(field.fieldName, field.headerName);
|
|
1354
|
+
}
|
|
1355
|
+
});
|
|
1356
|
+
// Seřadíme columnDefs podle pořadí z columnState a upravíme headerName podle savedFields
|
|
1357
|
+
baseColumnDefs = [...columnDefsToUse]
|
|
1358
|
+
.sort((a, b) => {
|
|
1359
|
+
const fieldA = a.field || a.colId;
|
|
1360
|
+
const fieldB = b.field || b.colId;
|
|
1361
|
+
const aState = columnStateMap.get(fieldA);
|
|
1362
|
+
const bState = columnStateMap.get(fieldB);
|
|
1363
|
+
const aOrder = aState?.__order ?? 999;
|
|
1364
|
+
const bOrder = bState?.__order ?? 999;
|
|
1365
|
+
return aOrder - bOrder;
|
|
1366
|
+
})
|
|
1367
|
+
.map((colDef) => {
|
|
1368
|
+
const fieldId = colDef.field || colDef.colId;
|
|
1369
|
+
const columnStateItem = columnStateMap.get(fieldId);
|
|
1370
|
+
// Aplikujeme pouze headerName a hide z API (width se aplikuje až v applySavedLayout)
|
|
1371
|
+
if (fieldId && (headerNameMap.has(fieldId) || columnStateItem)) {
|
|
1372
|
+
return {
|
|
1373
|
+
...colDef,
|
|
1374
|
+
// Aplikujeme headerName z savedFields
|
|
1375
|
+
...(headerNameMap.has(fieldId) && { headerName: headerNameMap.get(fieldId) }),
|
|
1376
|
+
// Aplikujeme hide hodnotu z columnState (z API show hodnoty)
|
|
1377
|
+
...(columnStateItem && { hide: columnStateItem.hide }),
|
|
1378
|
+
// Width se neaplikuje zde - aplikuje se až v applySavedLayout pro eliminaci konfliktu s resize
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1381
|
+
return colDef;
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
// Nyní VŽDY aplikujeme AgGridColumns transformaci PŘÍMO zde místo v props
|
|
1386
|
+
// Tím eliminujeme circular dependency pro všechny případy použití
|
|
1387
|
+
if (!Array.isArray(baseColumnDefs)) {
|
|
1388
|
+
// Pokud baseColumnDefs není array, mohlo by to být ColumnBuilder
|
|
1389
|
+
if (baseColumnDefs && typeof baseColumnDefs.build === 'function') {
|
|
1390
|
+
baseColumnDefs = baseColumnDefs.build();
|
|
1391
|
+
}
|
|
1392
|
+
else {
|
|
1393
|
+
return [];
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
return baseColumnDefs;
|
|
1397
|
+
// // Replikujeme AgGridColumns logiku pro všechny column definitions:
|
|
1398
|
+
// const processedColumns = baseColumnDefs?.map((column) => {
|
|
1399
|
+
// // Zkopírujeme column aby se předešlo mutacím
|
|
1400
|
+
// const processedColumn = { ...column };
|
|
1401
|
+
// // Aplikujeme tooltip logiku pokud je potřeba
|
|
1402
|
+
// if (processedColumn.contentTooltip) {
|
|
1403
|
+
// // Statické mapování tooltipů pro lepší performance a eliminaci circular dependency
|
|
1404
|
+
// switch (processedColumn.contentTooltip) {
|
|
1405
|
+
// case 'User':
|
|
1406
|
+
// processedColumn.tooltipComponent = Tooltip.User;
|
|
1407
|
+
// break;
|
|
1408
|
+
// default:
|
|
1409
|
+
// console.warn(`[GridLayout] Unknown tooltip component: ${processedColumn.contentTooltip}`);
|
|
1410
|
+
// }
|
|
1411
|
+
// }
|
|
1412
|
+
// return processedColumn;
|
|
1413
|
+
// }) || [];
|
|
1414
|
+
// return processedColumns;
|
|
1415
|
+
}, [waitForSavedFields, savedFields?.records, columnDefs, gridLayoutApi, lastColumnDefsHash]);
|
|
1416
|
+
/**
|
|
1417
|
+
* Handler pro změnu zobrazených dat - aktualizace headerName
|
|
1418
|
+
*/
|
|
1419
|
+
const handleRowDataChanged = useCallback((params) => {
|
|
1420
|
+
// if (!enabled || !savedFields?.records || !isInitialized) return;
|
|
1421
|
+
// console.log('[GridLayout] Row data changed - ensuring header names stay updated');
|
|
1422
|
+
// // Počkáme chvíli, až se vše vyrenderuje, a pak aktualizujeme headerName
|
|
1423
|
+
// setTimeout(() => {
|
|
1424
|
+
// try {
|
|
1425
|
+
// // Vytvoříme mapu fieldName -> headerName z API dat
|
|
1426
|
+
// const headerNameMap = new Map();
|
|
1427
|
+
// savedFields.records.forEach(field => {
|
|
1428
|
+
// if (field.fieldName && field.headerName) {
|
|
1429
|
+
// headerNameMap.set(field.fieldName, field.headerName);
|
|
1430
|
+
// }
|
|
1431
|
+
// });
|
|
1432
|
+
// // Najdeme všechny hlavičky sloupců v DOM
|
|
1433
|
+
// const headerCells = document.querySelectorAll('.ag-header-cell');
|
|
1434
|
+
// console.log('[GridLayout] Found header cells after data change:', headerCells.length);
|
|
1435
|
+
// // Aktualizujeme texty hlaviček
|
|
1436
|
+
// headerCells.forEach(headerCell => {
|
|
1437
|
+
// try {
|
|
1438
|
+
// // Získáme ID sloupce z DOM atributů
|
|
1439
|
+
// const colId = headerCell.getAttribute('col-id');
|
|
1440
|
+
// if (colId && headerNameMap.has(colId)) {
|
|
1441
|
+
// // Najdeme element s textem hlavičky
|
|
1442
|
+
// const headerTextEl = headerCell.querySelector('.ag-header-cell-text');
|
|
1443
|
+
// if (headerTextEl) {
|
|
1444
|
+
// const newHeaderName = headerNameMap.get(colId);
|
|
1445
|
+
// const currentText = headerTextEl.textContent;
|
|
1446
|
+
// if (currentText !== newHeaderName) {
|
|
1447
|
+
// console.log(`[GridLayout] Data change update: Column '${colId}' header from '${currentText}' to '${newHeaderName}'`);
|
|
1448
|
+
// headerTextEl.textContent = newHeaderName;
|
|
1449
|
+
// }
|
|
1450
|
+
// }
|
|
1451
|
+
// }
|
|
1452
|
+
// } catch (cellError) {
|
|
1453
|
+
// console.error('[GridLayout] Error updating header cell after data change:', cellError);
|
|
1454
|
+
// }
|
|
1455
|
+
// });
|
|
1456
|
+
// // Zkusíme vynutit překreslení hlavičky
|
|
1457
|
+
// if (typeof gridApiRef.current.refreshHeader === 'function') {
|
|
1458
|
+
// console.log('[GridLayout] Forcing header refresh after data change');
|
|
1459
|
+
// gridApiRef.current.refreshHeader();
|
|
1460
|
+
// }
|
|
1461
|
+
// } catch (error) {
|
|
1462
|
+
// console.error('[GridLayout] Error updating headers after data change:', error);
|
|
1463
|
+
// }
|
|
1464
|
+
// }, 100);
|
|
1465
|
+
}, [enabled, savedFields, isInitialized]);
|
|
512
1466
|
return {
|
|
513
1467
|
// State
|
|
514
1468
|
isLoading: isLoading || isFieldsLoading,
|
|
515
1469
|
isSaving,
|
|
1470
|
+
isApplyingLayout, // Nový specifický state pro aplikování layoutu
|
|
516
1471
|
error,
|
|
517
1472
|
hasUnsavedChanges,
|
|
518
1473
|
isInitialized,
|
|
1474
|
+
isGridReady, // Nový stav pro rychlejší aktivaci event handlerů
|
|
519
1475
|
shouldShowColumns, // Nové pole pro řízení zobrazení columnDefs
|
|
520
1476
|
preTransformedColumnDefs, // Pre-transformované columnDefs pro waitForSavedFields
|
|
521
1477
|
// AG-Grid event handlers
|
|
@@ -525,6 +1481,7 @@ onLayoutLoaded, onLayoutSaved, onError }) => {
|
|
|
525
1481
|
onColumnResized: handleColumnResized,
|
|
526
1482
|
onColumnVisible: handleColumnVisible,
|
|
527
1483
|
onColumnPinned: handleColumnPinned,
|
|
1484
|
+
onRowDataChanged: handleRowDataChanged, // Nový handler pro změnu dat
|
|
528
1485
|
// Manual actions
|
|
529
1486
|
saveLayout,
|
|
530
1487
|
resetToDefault,
|
|
@@ -539,7 +1496,7 @@ onLayoutLoaded, onLayoutSaved, onError }) => {
|
|
|
539
1496
|
savedFields: savedFields?.records || [],
|
|
540
1497
|
columnDefs, // Původní columnDefs pro Column Editor
|
|
541
1498
|
// Utils
|
|
542
|
-
gridLayoutApi
|
|
1499
|
+
gridLayoutApi,
|
|
543
1500
|
};
|
|
544
1501
|
};
|
|
545
1502
|
export default useGridLayout;
|