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