@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.
@@ -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 && columnDefs !== null && !Array.isArray(columnDefs)) {
31
- console.error('useGridLayout: columnDefs musí být array, získán:', typeof columnDefs, columnDefs);
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 || colDef.field || `Column ${index + 1}`,
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
- })), { enabled: enabled && !!userKey && !!gridName && Array.isArray(columnDefs) && columnDefs.length > 0 });
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(`Grid Layout Error ${context}:`, 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 || !columnApiRef.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
- const columnState = columnApiRef.current.getColumnState();
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 = gridLayoutApi.transformColumnStateToFields(columnState, columnDefs);
433
+ const fields = stableGridLayoutApiRef.current.transformColumnStateToFields(columnState, columnDefsToUse);
84
434
  // 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);
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
- handleError(error, 'při ukládání layoutu');
450
+ stableHandleErrorRef.current(error, 'při ukládání layoutu');
95
451
  }
96
452
  finally {
97
453
  setIsSaving(false);
98
454
  }
99
- }, [enabled, columnDefs, gridLayoutApi, onLayoutSaved, handleError]);
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(() => debounce(saveCurrentLayout, autoSaveDelay), [saveCurrentLayout, autoSaveDelay]);
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
- if (!savedFields?.records || !columnApiRef.current || isInitialized)
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
- const columnState = gridLayoutApi.transformFieldsToColumnState(savedFields.records, columnDefs);
114
- console.log("🚀 ~ useGridLayout ~ columnState:", savedFields.records, columnDefs, columnState);
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
- 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
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
- result = columnApiRef.current.applyColumnState({
146
- state: columnState,
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
- console.log("test2.5 - applyColumnState executed");
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("❌ Error applying column state:", delayedError);
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
- }, [savedFields, gridLayoutApi, isInitialized, onLayoutLoaded, handleError, columnDefs, waitForSavedFields]);
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 || !isInitialized)
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, isInitialized]);
730
+ }, [enabled, isGridReady]);
205
731
  const handleDragStopped = useCallback(() => {
206
- if (!enabled || !isInitialized)
732
+ if (!enabled || !isGridReady) {
207
733
  return;
734
+ }
208
735
  setHasUnsavedChanges(true);
209
- if (autoSave) {
210
- console.log("🎯 Drag stopped - spouštím debounced save");
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
- }, [enabled, isInitialized, autoSave, debouncedSave]);
781
+ else {
782
+ }
783
+ }, [enabled, isGridReady, isInitialized, autoSave, debouncedSave]);
214
784
  const handleColumnResized = useCallback(() => {
215
- if (!enabled || !isInitialized)
785
+ if (!enabled || !isGridReady)
216
786
  return;
217
787
  setHasUnsavedChanges(true);
218
- if (autoSave) {
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 || !isInitialized)
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 || !isInitialized)
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 když se načtou data
858
+ * Effect pro aplikování layoutu při prvotním načtení savedFields
253
859
  */
254
860
  useEffect(() => {
255
- if (savedFields?.records && columnApiRef.current && !isInitialized) {
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, applySavedLayout, isInitialized]);
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 || !columnApiRef.current)
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
- columnApiRef.current.resetColumnState();
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
- 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
- }));
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
- // 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,
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
- 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]);
1185
+ }, [columnDefs, savedFields, lastKnownColumnState]);
388
1186
  /**
389
1187
  * Otevře Column Editor modal
390
1188
  */
391
1189
  const openColumnEditor = useCallback(() => {
392
- console.log("🚀 Opening Column Editor", {
393
- hasColumnApiRef: !!columnApiRef.current,
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
- }, [isInitialized, columnDefs]);
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 = useCallback(async (editedColumns) => {
410
- console.log("🚀 ~ useGridLayout ~ editedColumns:", editedColumns);
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
- // 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) => ({
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, // Editovaný název nebo fallback na 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 || null
1223
+ Width: col.width != null ? col.width : null, // Zachováváme i nulovou šířku
1224
+ System: false,
444
1225
  }));
445
- // Uložíme změny přímo pomocí API
446
- if (autoSave) {
447
- const result = await gridLayoutApi.saveGridLayout(userFields);
1226
+ // Uložení do API
1227
+ gridLayoutApi
1228
+ .saveGridLayout(completeUserFields)
1229
+ .then((result) => {
448
1230
  if (result.success) {
449
1231
  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
- }
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(userFields, columnState);
1307
+ onLayoutSaved(completeUserFields);
460
1308
  }
461
1309
  }
462
- }
463
- else {
464
- setHasUnsavedChanges(true);
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 aplikování změn z Column Editoru');
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
- }, [enabled, autoSave, gridLayoutApi, onLayoutSaved, handleError, userKey, applicationName, gridName, filterName, refetchFields]);
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
- if (!waitForSavedFields || !savedFields?.records || !Array.isArray(columnDefs)) {
485
- return columnDefs; // Normální columnDefs
486
- }
487
- // Transformujeme columnDefs podle savedFields PŘED zobrazením gridu
488
- const columnState = gridLayoutApi.transformFieldsToColumnState(savedFields.records, columnDefs);
489
- if (!columnState || columnState.length === 0) {
490
- return columnDefs; // Pokud není co transformovat, vrátíme původní
491
- }
492
- // Vytvoříme mapu pro rychlé vyhledávání
493
- const columnStateMap = new Map();
494
- columnState.forEach((colState, index) => {
495
- columnStateMap.set(colState.colId, { ...colState, __order: index });
496
- });
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);
501
- const aOrder = aState?.__order ?? 999;
502
- const bOrder = bState?.__order ?? 999;
503
- 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)
509
- });
510
- return sortedColumnDefs;
511
- }, [waitForSavedFields, savedFields?.records, columnDefs, gridLayoutApi]);
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;