@bit.rhplus/ui.grid-layout 0.0.2 → 0.0.4

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