@bit.rhplus/ui.grid 0.0.52 → 0.0.54
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/ColumnBuilder.jsx
CHANGED
|
@@ -1,1280 +1,1294 @@
|
|
|
1
|
-
/* eslint-disable */
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import Menu from 'antd/es/menu';
|
|
4
|
-
import Dropdown from 'antd/es/dropdown';
|
|
5
|
-
import Button from 'antd/es/button';
|
|
6
|
-
import Divider from 'antd/es/divider';
|
|
7
|
-
import { prepareCellStyle, prepareColDef, getValueByPath } from './functions';
|
|
8
|
-
import { currencySymbols } from './enums';
|
|
9
|
-
import { ActionIcon } from './Icons';
|
|
10
|
-
import { CircleHelp, Check, X } from 'lucide-react';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Custom React hook pro zpracování interakcí s link buňkou v AG Grid.
|
|
14
|
-
* Obsluhuje hover efekty, kliky a přepínání overview módu.
|
|
15
|
-
* @param {Object} params - AG Grid parametry buňky
|
|
16
|
-
* @param {Function} onClick - Callback funkce při kliku na link
|
|
17
|
-
* @param {Object|Function} linkStyle - CSS styl pro link nebo funkce vracející styl
|
|
18
|
-
* @param {Object|Function} hoverStyle - CSS styl pro hover stav nebo funkce vracející styl
|
|
19
|
-
* @param {boolean} overviewToggle - Příznak zda aktivovat overview toggle funkčnost
|
|
20
|
-
* @returns {Object} Objekt s handlry a styly pro link buňku
|
|
21
|
-
*/
|
|
22
|
-
const useLinkCellRenderer = (
|
|
23
|
-
params,
|
|
24
|
-
onClick,
|
|
25
|
-
linkStyle,
|
|
26
|
-
hoverStyle,
|
|
27
|
-
overviewToggle
|
|
28
|
-
) => {
|
|
29
|
-
const [isHovered, setIsHovered] = React.useState(false);
|
|
30
|
-
|
|
31
|
-
const handleMouseEnter = React.useCallback(() => {
|
|
32
|
-
setIsHovered(true);
|
|
33
|
-
}, []);
|
|
34
|
-
|
|
35
|
-
const handleMouseLeave = React.useCallback(() => {
|
|
36
|
-
setIsHovered(false);
|
|
37
|
-
}, []);
|
|
38
|
-
|
|
39
|
-
const handleClick = React.useCallback(
|
|
40
|
-
(event) => {
|
|
41
|
-
event.stopPropagation();
|
|
42
|
-
|
|
43
|
-
if (overviewToggle && params.api) {
|
|
44
|
-
params.api.dispatchEvent({
|
|
45
|
-
type: 'overviewToggle',
|
|
46
|
-
data: params.data,
|
|
47
|
-
params,
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (onClick) {
|
|
52
|
-
onClick(params);
|
|
53
|
-
}
|
|
54
|
-
},
|
|
55
|
-
[onClick, overviewToggle, params]
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
// Přesunuto do useMemo, aby se vytvořilo pouze jednou
|
|
59
|
-
const defaultLinkStyle = React.useMemo(
|
|
60
|
-
() => ({
|
|
61
|
-
color: '#1a73e8',
|
|
62
|
-
textDecoration: 'none',
|
|
63
|
-
cursor: 'pointer',
|
|
64
|
-
}),
|
|
65
|
-
[]
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
// Přesunuto do useMemo, aby se vytvořilo pouze jednou
|
|
69
|
-
const defaultHoverStyle = React.useMemo(
|
|
70
|
-
() => ({
|
|
71
|
-
textDecoration: 'underline',
|
|
72
|
-
}),
|
|
73
|
-
[]
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
const computedLinkStyle = React.useMemo(
|
|
77
|
-
() => ({
|
|
78
|
-
...defaultLinkStyle,
|
|
79
|
-
...(typeof linkStyle === 'function'
|
|
80
|
-
? linkStyle(params)
|
|
81
|
-
: linkStyle || {}),
|
|
82
|
-
}),
|
|
83
|
-
[linkStyle, params, defaultLinkStyle]
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
const computedHoverStyle = React.useMemo(
|
|
87
|
-
() => ({
|
|
88
|
-
...defaultLinkStyle,
|
|
89
|
-
...computedLinkStyle,
|
|
90
|
-
...defaultHoverStyle,
|
|
91
|
-
...(typeof hoverStyle === 'function'
|
|
92
|
-
? hoverStyle(params)
|
|
93
|
-
: hoverStyle || {}),
|
|
94
|
-
}),
|
|
95
|
-
[computedLinkStyle, hoverStyle, params, defaultLinkStyle, defaultHoverStyle]
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
return {
|
|
99
|
-
isHovered,
|
|
100
|
-
handleMouseEnter,
|
|
101
|
-
handleMouseLeave,
|
|
102
|
-
handleClick,
|
|
103
|
-
computedLinkStyle,
|
|
104
|
-
computedHoverStyle,
|
|
105
|
-
};
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Custom React hook pro zpracování interakcí s object buňkou v AG Grid.
|
|
110
|
-
* Poskytuje funkcionalitu pro editovatelné objekty s hover efekty a edit tlačítkem.
|
|
111
|
-
* @param {Object} params - AG Grid parametry buňky
|
|
112
|
-
* @param {boolean} editable - Příznak zda je buňka editovatelná
|
|
113
|
-
* @param {Function} onEditClick - Callback funkce při kliku na edit tlačítko
|
|
114
|
-
* @returns {Object} Objekt s handlry pro object buňku
|
|
115
|
-
*/
|
|
116
|
-
const useObjectCellRenderer = (params, editable, onEditClick) => {
|
|
117
|
-
const [isHovered, setIsHovered] = React.useState(false);
|
|
118
|
-
|
|
119
|
-
const handleMouseEnter = React.useCallback(() => {
|
|
120
|
-
setIsHovered(true);
|
|
121
|
-
}, []);
|
|
122
|
-
|
|
123
|
-
const handleMouseLeave = React.useCallback(() => {
|
|
124
|
-
setIsHovered(false);
|
|
125
|
-
}, []);
|
|
126
|
-
|
|
127
|
-
const handleEditClick = React.useCallback(
|
|
128
|
-
(event) => {
|
|
129
|
-
event.stopPropagation();
|
|
130
|
-
if (onEditClick) {
|
|
131
|
-
onEditClick(params);
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
[onEditClick, params]
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
isHovered,
|
|
139
|
-
handleMouseEnter,
|
|
140
|
-
handleMouseLeave,
|
|
141
|
-
handleEditClick,
|
|
142
|
-
};
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Custom React hook pro detekci hover stavu řádku v AG Grid.
|
|
147
|
-
* Používá MutationObserver pro sledování CSS tříd řádků a detekci hover stavu.
|
|
148
|
-
* Tento hook se používá pro akční tlačítka, která se zobrazují pouze při hoveru nad řádkem.
|
|
149
|
-
* @param {Object} params - AG Grid parametry buňky obsahující informace o řádku
|
|
150
|
-
* @returns {Object} Objekt s boolean příznakem isRowHovered
|
|
151
|
-
*/
|
|
152
|
-
const useRowHoverActionRenderer = (params) => {
|
|
153
|
-
const [isRowHovered, setIsRowHovered] = React.useState(false);
|
|
154
|
-
const rowRef = React.useRef(null);
|
|
155
|
-
|
|
156
|
-
React.useEffect(() => {
|
|
157
|
-
if (!params.node) return undefined;
|
|
158
|
-
|
|
159
|
-
// Funkce pro kontrolu, zda je řádek v hover stavu
|
|
160
|
-
const checkRowHoverState = () => {
|
|
161
|
-
// Najdeme DOM element řádku pomocí rowIndex
|
|
162
|
-
const rowElement = document.querySelector(
|
|
163
|
-
`.ag-row[row-index="${params.rowIndex}"]`
|
|
164
|
-
);
|
|
165
|
-
if (rowElement) {
|
|
166
|
-
rowRef.current = rowElement;
|
|
167
|
-
// AG-Grid automaticky přidává třídu ag-row-hover k řádku při najetí myší
|
|
168
|
-
const isHovered = rowElement.classList.contains('ag-row-hover');
|
|
169
|
-
setIsRowHovered(isHovered);
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
// Vytvoříme MutationObserver pro sledování změn tříd na řádku
|
|
174
|
-
const observer = new MutationObserver((mutations) => {
|
|
175
|
-
mutations.forEach((mutation) => {
|
|
176
|
-
if (
|
|
177
|
-
mutation.type === 'attributes' &&
|
|
178
|
-
mutation.attributeName === 'class'
|
|
179
|
-
) {
|
|
180
|
-
checkRowHoverState();
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
// Inicializujeme stav
|
|
186
|
-
checkRowHoverState();
|
|
187
|
-
|
|
188
|
-
// Přidáme observer k element řádku, pokud existuje
|
|
189
|
-
if (rowRef.current) {
|
|
190
|
-
observer.observe(rowRef.current, { attributes: true });
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Přidáme event listeners na grid container pro sledování pohybu myši
|
|
194
|
-
const gridContainer = document.querySelector('.ag-root-wrapper');
|
|
195
|
-
if (gridContainer) {
|
|
196
|
-
gridContainer.addEventListener('mouseover', checkRowHoverState);
|
|
197
|
-
gridContainer.addEventListener('mouseout', checkRowHoverState);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Cleanup při odmontování komponenty
|
|
201
|
-
return () => {
|
|
202
|
-
if (rowRef.current) {
|
|
203
|
-
observer.disconnect();
|
|
204
|
-
}
|
|
205
|
-
if (gridContainer) {
|
|
206
|
-
gridContainer.removeEventListener('mouseover', checkRowHoverState);
|
|
207
|
-
gridContainer.removeEventListener('mouseout', checkRowHoverState);
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
}, [params.node, params.rowIndex]);
|
|
211
|
-
|
|
212
|
-
return {
|
|
213
|
-
isRowHovered,
|
|
214
|
-
};
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* ColumnBuilder třída pro builder pattern vytváření sloupců AG Grid.
|
|
219
|
-
* Poskytuje fluent API pro snadné a čitelné definování různých typů sloupců.
|
|
220
|
-
* Podporuje lokalizaci přes react-intl a automatickou konfiguraci sloupců.
|
|
221
|
-
*/
|
|
222
|
-
class ColumnBuilder {
|
|
223
|
-
/**
|
|
224
|
-
* Privátní metoda pro přidání připraveného sloupce do kolekce.
|
|
225
|
-
* Aplikuje standardní konfiguraci sloupce včetně lokalizace.
|
|
226
|
-
* @param {Object} props - Konfigurace sloupce
|
|
227
|
-
*/
|
|
228
|
-
#addPreparedColumn(props) {
|
|
229
|
-
this.columns.push(prepareColDef(this.intl, props));
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Konstruktor ColumnBuilder třídy.
|
|
234
|
-
* @param {Object} intl - React-intl objekt pro lokalizaci
|
|
235
|
-
*/
|
|
236
|
-
constructor(intl) {
|
|
237
|
-
this.columns = [];
|
|
238
|
-
this.intl = intl;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Přidá základní sloupec do AG Grid s podporou barevného pole.
|
|
243
|
-
* Umožňuje dynamické obarvení textu buňky na základě hodnoty z jiného pole.
|
|
244
|
-
* @param {Object} config - Konfigurace sloupce
|
|
245
|
-
* @param {string} config.colorField - Název pole obsahujícího barvu pro text buňky
|
|
246
|
-
* @param {
|
|
247
|
-
* @
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const
|
|
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
|
-
* @param {
|
|
624
|
-
* @param {
|
|
625
|
-
* @param {
|
|
626
|
-
* @
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
*
|
|
731
|
-
*
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
display: 'flex',
|
|
1180
|
-
alignItems: 'center',
|
|
1181
|
-
justifyContent: 'center',
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import Menu from 'antd/es/menu';
|
|
4
|
+
import Dropdown from 'antd/es/dropdown';
|
|
5
|
+
import Button from 'antd/es/button';
|
|
6
|
+
import Divider from 'antd/es/divider';
|
|
7
|
+
import { prepareCellStyle, prepareColDef, getValueByPath } from './functions';
|
|
8
|
+
import { currencySymbols } from './enums';
|
|
9
|
+
import { ActionIcon } from './Icons';
|
|
10
|
+
import { CircleHelp, Check, X } from 'lucide-react';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Custom React hook pro zpracování interakcí s link buňkou v AG Grid.
|
|
14
|
+
* Obsluhuje hover efekty, kliky a přepínání overview módu.
|
|
15
|
+
* @param {Object} params - AG Grid parametry buňky
|
|
16
|
+
* @param {Function} onClick - Callback funkce při kliku na link
|
|
17
|
+
* @param {Object|Function} linkStyle - CSS styl pro link nebo funkce vracející styl
|
|
18
|
+
* @param {Object|Function} hoverStyle - CSS styl pro hover stav nebo funkce vracející styl
|
|
19
|
+
* @param {boolean} overviewToggle - Příznak zda aktivovat overview toggle funkčnost
|
|
20
|
+
* @returns {Object} Objekt s handlry a styly pro link buňku
|
|
21
|
+
*/
|
|
22
|
+
const useLinkCellRenderer = (
|
|
23
|
+
params,
|
|
24
|
+
onClick,
|
|
25
|
+
linkStyle,
|
|
26
|
+
hoverStyle,
|
|
27
|
+
overviewToggle
|
|
28
|
+
) => {
|
|
29
|
+
const [isHovered, setIsHovered] = React.useState(false);
|
|
30
|
+
|
|
31
|
+
const handleMouseEnter = React.useCallback(() => {
|
|
32
|
+
setIsHovered(true);
|
|
33
|
+
}, []);
|
|
34
|
+
|
|
35
|
+
const handleMouseLeave = React.useCallback(() => {
|
|
36
|
+
setIsHovered(false);
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
const handleClick = React.useCallback(
|
|
40
|
+
(event) => {
|
|
41
|
+
event.stopPropagation();
|
|
42
|
+
|
|
43
|
+
if (overviewToggle && params.api) {
|
|
44
|
+
params.api.dispatchEvent({
|
|
45
|
+
type: 'overviewToggle',
|
|
46
|
+
data: params.data,
|
|
47
|
+
params,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (onClick) {
|
|
52
|
+
onClick(params);
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
[onClick, overviewToggle, params]
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// Přesunuto do useMemo, aby se vytvořilo pouze jednou
|
|
59
|
+
const defaultLinkStyle = React.useMemo(
|
|
60
|
+
() => ({
|
|
61
|
+
color: '#1a73e8',
|
|
62
|
+
textDecoration: 'none',
|
|
63
|
+
cursor: 'pointer',
|
|
64
|
+
}),
|
|
65
|
+
[]
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// Přesunuto do useMemo, aby se vytvořilo pouze jednou
|
|
69
|
+
const defaultHoverStyle = React.useMemo(
|
|
70
|
+
() => ({
|
|
71
|
+
textDecoration: 'underline',
|
|
72
|
+
}),
|
|
73
|
+
[]
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const computedLinkStyle = React.useMemo(
|
|
77
|
+
() => ({
|
|
78
|
+
...defaultLinkStyle,
|
|
79
|
+
...(typeof linkStyle === 'function'
|
|
80
|
+
? linkStyle(params)
|
|
81
|
+
: linkStyle || {}),
|
|
82
|
+
}),
|
|
83
|
+
[linkStyle, params, defaultLinkStyle]
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const computedHoverStyle = React.useMemo(
|
|
87
|
+
() => ({
|
|
88
|
+
...defaultLinkStyle,
|
|
89
|
+
...computedLinkStyle,
|
|
90
|
+
...defaultHoverStyle,
|
|
91
|
+
...(typeof hoverStyle === 'function'
|
|
92
|
+
? hoverStyle(params)
|
|
93
|
+
: hoverStyle || {}),
|
|
94
|
+
}),
|
|
95
|
+
[computedLinkStyle, hoverStyle, params, defaultLinkStyle, defaultHoverStyle]
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
isHovered,
|
|
100
|
+
handleMouseEnter,
|
|
101
|
+
handleMouseLeave,
|
|
102
|
+
handleClick,
|
|
103
|
+
computedLinkStyle,
|
|
104
|
+
computedHoverStyle,
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Custom React hook pro zpracování interakcí s object buňkou v AG Grid.
|
|
110
|
+
* Poskytuje funkcionalitu pro editovatelné objekty s hover efekty a edit tlačítkem.
|
|
111
|
+
* @param {Object} params - AG Grid parametry buňky
|
|
112
|
+
* @param {boolean} editable - Příznak zda je buňka editovatelná
|
|
113
|
+
* @param {Function} onEditClick - Callback funkce při kliku na edit tlačítko
|
|
114
|
+
* @returns {Object} Objekt s handlry pro object buňku
|
|
115
|
+
*/
|
|
116
|
+
const useObjectCellRenderer = (params, editable, onEditClick) => {
|
|
117
|
+
const [isHovered, setIsHovered] = React.useState(false);
|
|
118
|
+
|
|
119
|
+
const handleMouseEnter = React.useCallback(() => {
|
|
120
|
+
setIsHovered(true);
|
|
121
|
+
}, []);
|
|
122
|
+
|
|
123
|
+
const handleMouseLeave = React.useCallback(() => {
|
|
124
|
+
setIsHovered(false);
|
|
125
|
+
}, []);
|
|
126
|
+
|
|
127
|
+
const handleEditClick = React.useCallback(
|
|
128
|
+
(event) => {
|
|
129
|
+
event.stopPropagation();
|
|
130
|
+
if (onEditClick) {
|
|
131
|
+
onEditClick(params);
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
[onEditClick, params]
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
isHovered,
|
|
139
|
+
handleMouseEnter,
|
|
140
|
+
handleMouseLeave,
|
|
141
|
+
handleEditClick,
|
|
142
|
+
};
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Custom React hook pro detekci hover stavu řádku v AG Grid.
|
|
147
|
+
* Používá MutationObserver pro sledování CSS tříd řádků a detekci hover stavu.
|
|
148
|
+
* Tento hook se používá pro akční tlačítka, která se zobrazují pouze při hoveru nad řádkem.
|
|
149
|
+
* @param {Object} params - AG Grid parametry buňky obsahující informace o řádku
|
|
150
|
+
* @returns {Object} Objekt s boolean příznakem isRowHovered
|
|
151
|
+
*/
|
|
152
|
+
const useRowHoverActionRenderer = (params) => {
|
|
153
|
+
const [isRowHovered, setIsRowHovered] = React.useState(false);
|
|
154
|
+
const rowRef = React.useRef(null);
|
|
155
|
+
|
|
156
|
+
React.useEffect(() => {
|
|
157
|
+
if (!params.node) return undefined;
|
|
158
|
+
|
|
159
|
+
// Funkce pro kontrolu, zda je řádek v hover stavu
|
|
160
|
+
const checkRowHoverState = () => {
|
|
161
|
+
// Najdeme DOM element řádku pomocí rowIndex
|
|
162
|
+
const rowElement = document.querySelector(
|
|
163
|
+
`.ag-row[row-index="${params.rowIndex}"]`
|
|
164
|
+
);
|
|
165
|
+
if (rowElement) {
|
|
166
|
+
rowRef.current = rowElement;
|
|
167
|
+
// AG-Grid automaticky přidává třídu ag-row-hover k řádku při najetí myší
|
|
168
|
+
const isHovered = rowElement.classList.contains('ag-row-hover');
|
|
169
|
+
setIsRowHovered(isHovered);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// Vytvoříme MutationObserver pro sledování změn tříd na řádku
|
|
174
|
+
const observer = new MutationObserver((mutations) => {
|
|
175
|
+
mutations.forEach((mutation) => {
|
|
176
|
+
if (
|
|
177
|
+
mutation.type === 'attributes' &&
|
|
178
|
+
mutation.attributeName === 'class'
|
|
179
|
+
) {
|
|
180
|
+
checkRowHoverState();
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Inicializujeme stav
|
|
186
|
+
checkRowHoverState();
|
|
187
|
+
|
|
188
|
+
// Přidáme observer k element řádku, pokud existuje
|
|
189
|
+
if (rowRef.current) {
|
|
190
|
+
observer.observe(rowRef.current, { attributes: true });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Přidáme event listeners na grid container pro sledování pohybu myši
|
|
194
|
+
const gridContainer = document.querySelector('.ag-root-wrapper');
|
|
195
|
+
if (gridContainer) {
|
|
196
|
+
gridContainer.addEventListener('mouseover', checkRowHoverState);
|
|
197
|
+
gridContainer.addEventListener('mouseout', checkRowHoverState);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Cleanup při odmontování komponenty
|
|
201
|
+
return () => {
|
|
202
|
+
if (rowRef.current) {
|
|
203
|
+
observer.disconnect();
|
|
204
|
+
}
|
|
205
|
+
if (gridContainer) {
|
|
206
|
+
gridContainer.removeEventListener('mouseover', checkRowHoverState);
|
|
207
|
+
gridContainer.removeEventListener('mouseout', checkRowHoverState);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}, [params.node, params.rowIndex]);
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
isRowHovered,
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* ColumnBuilder třída pro builder pattern vytváření sloupců AG Grid.
|
|
219
|
+
* Poskytuje fluent API pro snadné a čitelné definování různých typů sloupců.
|
|
220
|
+
* Podporuje lokalizaci přes react-intl a automatickou konfiguraci sloupců.
|
|
221
|
+
*/
|
|
222
|
+
class ColumnBuilder {
|
|
223
|
+
/**
|
|
224
|
+
* Privátní metoda pro přidání připraveného sloupce do kolekce.
|
|
225
|
+
* Aplikuje standardní konfiguraci sloupce včetně lokalizace.
|
|
226
|
+
* @param {Object} props - Konfigurace sloupce
|
|
227
|
+
*/
|
|
228
|
+
#addPreparedColumn(props) {
|
|
229
|
+
this.columns.push(prepareColDef(this.intl, props));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Konstruktor ColumnBuilder třídy.
|
|
234
|
+
* @param {Object} intl - React-intl objekt pro lokalizaci
|
|
235
|
+
*/
|
|
236
|
+
constructor(intl) {
|
|
237
|
+
this.columns = [];
|
|
238
|
+
this.intl = intl;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Přidá základní sloupec do AG Grid s podporou barevného pole.
|
|
243
|
+
* Umožňuje dynamické obarvení textu buňky na základě hodnoty z jiného pole.
|
|
244
|
+
* @param {Object} config - Konfigurace sloupce
|
|
245
|
+
* @param {string} config.colorField - Název pole obsahujícího barvu pro text buňky
|
|
246
|
+
* @param {string} config.bgColorField - Název pole obsahujícího barvu pozadí buňky
|
|
247
|
+
* @param {Object} ...props - Další AG Grid vlastnosti sloupce
|
|
248
|
+
* @returns {ColumnBuilder} Instance pro chaining
|
|
249
|
+
*/
|
|
250
|
+
addColumn({ colorField, bgColorField, ...props }) {
|
|
251
|
+
// Získáme původní cellStyle, pokud existuje
|
|
252
|
+
const originalCellStyle = props.cellStyle;
|
|
253
|
+
const { cellAlign, ...restProps } = props;
|
|
254
|
+
|
|
255
|
+
// Pokud je zadáno colorField nebo bgColorField, vytvoříme novou funkci pro cellStyle
|
|
256
|
+
if (colorField || bgColorField) {
|
|
257
|
+
const overrideCellStyle = (params) => {
|
|
258
|
+
// Získáme základní styl
|
|
259
|
+
let baseStyle = {};
|
|
260
|
+
if (originalCellStyle) {
|
|
261
|
+
if (typeof originalCellStyle === 'function') {
|
|
262
|
+
baseStyle = originalCellStyle(params);
|
|
263
|
+
} else {
|
|
264
|
+
baseStyle = originalCellStyle;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Získáme hodnotu barvy textu z dat
|
|
269
|
+
const colorValue =
|
|
270
|
+
colorField && params.data ? getValueByPath(params.data, colorField) : null;
|
|
271
|
+
|
|
272
|
+
// Získáme hodnotu barvy pozadí z dat
|
|
273
|
+
const bgColorValue =
|
|
274
|
+
bgColorField && params.data ? getValueByPath(params.data, bgColorField) : null;
|
|
275
|
+
|
|
276
|
+
const restStyle = prepareCellStyle(props);
|
|
277
|
+
|
|
278
|
+
// Vrátíme kombinovaný styl s barvou textu i pozadí
|
|
279
|
+
const newStyle = { ...baseStyle, ...restStyle };
|
|
280
|
+
if (colorValue) {
|
|
281
|
+
newStyle.color = colorValue;
|
|
282
|
+
}
|
|
283
|
+
if (bgColorValue) {
|
|
284
|
+
newStyle.backgroundColor = bgColorValue;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return newStyle;
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
// Předáme upravené props do addPreparedColumn
|
|
291
|
+
this.#addPreparedColumn({ ...restProps, overrideCellStyle });
|
|
292
|
+
} else {
|
|
293
|
+
// Pokud není colorField ani bgColorField zadán, použijeme původní implementaci
|
|
294
|
+
this.#addPreparedColumn(props);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return this;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Přidá sloupec s kartou faktury optimalizovaný pro overview mód.
|
|
302
|
+
* Zobrazuje fakturační informace v kartovém formátu s podporou checkboxu.
|
|
303
|
+
* @param {Object} config - Konfigurace sloupce
|
|
304
|
+
* @param {string} [config.field='invoice'] - Název datového pole
|
|
305
|
+
* @param {string} [config.headerName=''] - Název hlavičky sloupce
|
|
306
|
+
* @param {number} [config.width=340] - Šířka sloupce
|
|
307
|
+
* @param {Function} config.onCheckboxChange - Callback při změně stavu checkboxu
|
|
308
|
+
* @param {Object} ...restProps - Další AG Grid vlastnosti sloupce
|
|
309
|
+
* @returns {ColumnBuilder} Instance pro chaining
|
|
310
|
+
*/
|
|
311
|
+
addInvoiceCardColumn({
|
|
312
|
+
field = 'invoice',
|
|
313
|
+
headerName = '',
|
|
314
|
+
width = 340,
|
|
315
|
+
onCheckboxChange,
|
|
316
|
+
...restProps
|
|
317
|
+
} = {}) {
|
|
318
|
+
const cellRenderer = 'invoiceCardRenderer';
|
|
319
|
+
|
|
320
|
+
this.#addPreparedColumn({
|
|
321
|
+
headerName,
|
|
322
|
+
field,
|
|
323
|
+
width,
|
|
324
|
+
cellRenderer,
|
|
325
|
+
suppressSizeToFit: true,
|
|
326
|
+
cellRendererParams: {
|
|
327
|
+
onCheckboxChange:
|
|
328
|
+
onCheckboxChange ||
|
|
329
|
+
(() => {
|
|
330
|
+
// Funkce bez console.log
|
|
331
|
+
}),
|
|
332
|
+
},
|
|
333
|
+
...restProps,
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
return this;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Přidá sloupec pro zobrazení měny s podporou různých formátů a pozicování symbolu.
|
|
341
|
+
* Automaticky formátuje hodnoty jako měnu s dvěma desetinnými místy.
|
|
342
|
+
* @param {Object} config - Konfigurace měnového sloupce
|
|
343
|
+
* @param {string|Function} config.currency - Kód měny nebo funkce vracející kód měny
|
|
344
|
+
* @param {string} [config.position] - Pozice symbolu měny ('left' nebo 'right')
|
|
345
|
+
* @param {Object|Function} config.currencyStyle - CSS styl pro symbol měny
|
|
346
|
+
* @param {string} [config.cellAlign='right'] - Zarovnání obsahu buňky
|
|
347
|
+
* @param {boolean} config.editable - Zda je sloupec editovatelný
|
|
348
|
+
* @param {Object} ...restProps - Další AG Grid vlastnosti sloupce
|
|
349
|
+
* @returns {ColumnBuilder} Instance pro chaining
|
|
350
|
+
*/
|
|
351
|
+
addCurrencyColumn({
|
|
352
|
+
currency,
|
|
353
|
+
position,
|
|
354
|
+
currencyStyle,
|
|
355
|
+
cellAlign = 'right',
|
|
356
|
+
editable,
|
|
357
|
+
...restProps
|
|
358
|
+
}) {
|
|
359
|
+
const cellRenderer = (params) => {
|
|
360
|
+
const currencyValue =
|
|
361
|
+
typeof currency === 'function' ? currency(params) : currency;
|
|
362
|
+
const symbol = currencySymbols[currencyValue] || currencyValue;
|
|
363
|
+
|
|
364
|
+
// Použití Number.isNaN místo globální isNaN
|
|
365
|
+
const value =
|
|
366
|
+
params.value != null && !Number.isNaN(Number(params.value))
|
|
367
|
+
? params.value.toFixed(2)
|
|
368
|
+
: '0.00';
|
|
369
|
+
|
|
370
|
+
const style =
|
|
371
|
+
typeof currencyStyle === 'function'
|
|
372
|
+
? currencyStyle(params)
|
|
373
|
+
: currencyStyle;
|
|
374
|
+
|
|
375
|
+
return (
|
|
376
|
+
<span>
|
|
377
|
+
{position === 'left' ? (
|
|
378
|
+
<>
|
|
379
|
+
<span style={style}>{symbol}</span> {value}
|
|
380
|
+
</>
|
|
381
|
+
) : (
|
|
382
|
+
<>
|
|
383
|
+
{value} <span style={style}>{symbol}</span>
|
|
384
|
+
</>
|
|
385
|
+
)}
|
|
386
|
+
</span>
|
|
387
|
+
);
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
this.#addPreparedColumn({
|
|
391
|
+
cellAlign,
|
|
392
|
+
cellRenderer,
|
|
393
|
+
currency,
|
|
394
|
+
editable: this.#resolveEditable(editable),
|
|
395
|
+
...restProps,
|
|
396
|
+
});
|
|
397
|
+
return this;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Přidá sloupec pro zobrazení data s možností specifikace formátu.
|
|
402
|
+
* Používá standardní AG Grid date renderer s českým formátováním.
|
|
403
|
+
* @param {Object} config - Konfigurace datového sloupce
|
|
404
|
+
* @param {string} [config.dateFormat='DD.MM.YYYY'] - Formát zobrazení data
|
|
405
|
+
* @param {boolean} config.editable - Zda je sloupec editovatelný
|
|
406
|
+
* @param {Object} ...restProps - Další AG Grid vlastnosti sloupce
|
|
407
|
+
* @returns {ColumnBuilder} Instance pro chaining
|
|
408
|
+
*/
|
|
409
|
+
addDateColumn({ dateFormat = 'DD.MM.YYYY', editable, ...restProps }) {
|
|
410
|
+
this.#addPreparedColumn({
|
|
411
|
+
dateRenderer: dateFormat,
|
|
412
|
+
editable: this.#resolveEditable(editable),
|
|
413
|
+
...restProps,
|
|
414
|
+
});
|
|
415
|
+
return this;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Přidá sloupec s klikatelným linkem podporujícím hover efekty.
|
|
420
|
+
* Link může spouštět akce nebo přepínat overview mód v gridu.
|
|
421
|
+
* @param {Object} config - Konfigurace linkového sloupce
|
|
422
|
+
* @param {Function} config.onClick - Callback funkce při kliku na link
|
|
423
|
+
* @param {Object|Function} config.linkStyle - CSS styl pro link nebo funkce vracející styl
|
|
424
|
+
* @param {Object|Function} config.hoverStyle - CSS styl pro hover stav
|
|
425
|
+
* @param {string} [config.cellAlign='left'] - Zarovnání obsahu buňky
|
|
426
|
+
* @param {boolean} config.editable - Zda je sloupec editovatelný
|
|
427
|
+
* @param {boolean} [config.overviewToggle=false] - Zda aktivovat overview toggle
|
|
428
|
+
* @param {Object} ...restProps - Další AG Grid vlastnosti sloupce
|
|
429
|
+
* @returns {ColumnBuilder} Instance pro chaining
|
|
430
|
+
*/
|
|
431
|
+
addLinkColumn({
|
|
432
|
+
onClick,
|
|
433
|
+
linkStyle,
|
|
434
|
+
hoverStyle,
|
|
435
|
+
cellAlign = 'left',
|
|
436
|
+
editable,
|
|
437
|
+
overviewToggle = false, // Přidán výchozí parametr pro overview
|
|
438
|
+
...restProps
|
|
439
|
+
}) {
|
|
440
|
+
// Vytvořím komponentu pro cell renderer, která používá hook
|
|
441
|
+
const LinkCellRenderer = React.memo((params) => {
|
|
442
|
+
const {
|
|
443
|
+
isHovered,
|
|
444
|
+
handleMouseEnter,
|
|
445
|
+
handleMouseLeave,
|
|
446
|
+
handleClick,
|
|
447
|
+
computedLinkStyle,
|
|
448
|
+
computedHoverStyle,
|
|
449
|
+
} = useLinkCellRenderer(
|
|
450
|
+
params,
|
|
451
|
+
onClick,
|
|
452
|
+
linkStyle,
|
|
453
|
+
hoverStyle,
|
|
454
|
+
overviewToggle
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
return (
|
|
458
|
+
<div
|
|
459
|
+
className="link-cell-container"
|
|
460
|
+
style={{
|
|
461
|
+
width: '100%',
|
|
462
|
+
height: '100%',
|
|
463
|
+
display: 'flex',
|
|
464
|
+
alignItems: 'center',
|
|
465
|
+
}}
|
|
466
|
+
>
|
|
467
|
+
<span
|
|
468
|
+
onClick={handleClick}
|
|
469
|
+
onMouseEnter={handleMouseEnter}
|
|
470
|
+
onMouseLeave={handleMouseLeave}
|
|
471
|
+
style={isHovered ? computedHoverStyle : computedLinkStyle}
|
|
472
|
+
role="button"
|
|
473
|
+
tabIndex={0}
|
|
474
|
+
onKeyPress={(event) => {
|
|
475
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
476
|
+
handleClick(event);
|
|
477
|
+
}
|
|
478
|
+
}}
|
|
479
|
+
>
|
|
480
|
+
{params.value}
|
|
481
|
+
</span>
|
|
482
|
+
</div>
|
|
483
|
+
);
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
// Používáme funkci, která vrátí React komponentu
|
|
487
|
+
const cellRenderer = (params) => {
|
|
488
|
+
return <LinkCellRenderer {...params} />;
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
this.#addPreparedColumn({
|
|
492
|
+
cellAlign,
|
|
493
|
+
cellRenderer,
|
|
494
|
+
editable: this.#resolveEditable(editable),
|
|
495
|
+
overviewToggle, // Předání příznaku dál
|
|
496
|
+
...restProps,
|
|
497
|
+
});
|
|
498
|
+
return this;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Helper metoda pro přidání overview link sloupce s přednastavenými hodnotami.
|
|
503
|
+
* Specializovaný link sloupec pro přepínání overview módu v gridu.
|
|
504
|
+
* @param {Object} config - Konfigurace overview link sloupce
|
|
505
|
+
* @param {string} [config.field='documentNumber'] - Název datového pole
|
|
506
|
+
* @param {string} [config.headerName=''] - Název hlavičky sloupce
|
|
507
|
+
* @param {number} [config.width=130] - Šířka sloupce
|
|
508
|
+
* @param {string} [config.cellAlign='left'] - Zarovnání obsahu buňky
|
|
509
|
+
* @param {Object|Function} config.linkStyle - CSS styl pro link
|
|
510
|
+
* @param {Object|Function} config.hoverStyle - CSS styl pro hover stav
|
|
511
|
+
* @param {boolean} [config.editable=false] - Zda je sloupec editovatelný
|
|
512
|
+
* @param {Object} ...rest - Další AG Grid vlastnosti sloupce včetně intlId
|
|
513
|
+
* @returns {ColumnBuilder} Instance pro chaining
|
|
514
|
+
*/
|
|
515
|
+
addOverviewLinkColumn({
|
|
516
|
+
field = 'documentNumber',
|
|
517
|
+
headerName = '',
|
|
518
|
+
width = 130,
|
|
519
|
+
cellAlign = 'left',
|
|
520
|
+
linkStyle,
|
|
521
|
+
hoverStyle,
|
|
522
|
+
editable = false,
|
|
523
|
+
...rest
|
|
524
|
+
} = {}) {
|
|
525
|
+
return this.addLinkColumn({
|
|
526
|
+
field,
|
|
527
|
+
headerName: this?.intl?.formatMessage({ id: rest?.intlId }) || headerName,
|
|
528
|
+
width,
|
|
529
|
+
cellAlign,
|
|
530
|
+
linkStyle,
|
|
531
|
+
hoverStyle,
|
|
532
|
+
editable,
|
|
533
|
+
overviewToggle: true,
|
|
534
|
+
...rest,
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Přidá sloupec pro zobrazení objektů s možností editace a tooltip podporou.
|
|
540
|
+
* Při hoveru zobrazuje edit tlačítko pro editovatelné objekty.
|
|
541
|
+
* @param {Object} config - Konfigurace objektového sloupce
|
|
542
|
+
* @param {boolean} config.contentTooltip - Zda zobrazovat tooltip s obsahem
|
|
543
|
+
* @param {string} config.tooltipField - Pole obsahující text pro tooltip
|
|
544
|
+
* @param {boolean} config.tooltipInteraction - Zda povolit interakci s tooltipem
|
|
545
|
+
* @param {number} [config.tooltipShowDelay=100] - Zpoždění zobrazení tooltipu v ms
|
|
546
|
+
* @param {boolean} config.editable - Zda je objekt editovatelný
|
|
547
|
+
* @param {Function} config.onEditClick - Callback při kliku na edit tlačítko
|
|
548
|
+
* @param {Object} ...restProps - Další AG Grid vlastnosti sloupce
|
|
549
|
+
* @returns {ColumnBuilder} Instance pro chaining
|
|
550
|
+
*/
|
|
551
|
+
addObjectColumn({
|
|
552
|
+
contentTooltip,
|
|
553
|
+
tooltipField,
|
|
554
|
+
tooltipInteraction,
|
|
555
|
+
tooltipShowDelay = 100,
|
|
556
|
+
editable,
|
|
557
|
+
onEditClick,
|
|
558
|
+
...restProps
|
|
559
|
+
}) {
|
|
560
|
+
// Vytvořím komponentu pro cell renderer, která používá hook
|
|
561
|
+
const ObjectCellRenderer = React.memo((params) => {
|
|
562
|
+
const { isHovered, handleMouseEnter, handleMouseLeave, handleEditClick } =
|
|
563
|
+
useObjectCellRenderer(params, editable, onEditClick);
|
|
564
|
+
|
|
565
|
+
return (
|
|
566
|
+
<div
|
|
567
|
+
className="object-cell-container"
|
|
568
|
+
style={{
|
|
569
|
+
position: 'relative',
|
|
570
|
+
width: '100%',
|
|
571
|
+
height: '100%',
|
|
572
|
+
display: 'flex',
|
|
573
|
+
alignItems: 'center',
|
|
574
|
+
}}
|
|
575
|
+
onMouseEnter={handleMouseEnter}
|
|
576
|
+
onMouseLeave={handleMouseLeave}
|
|
577
|
+
>
|
|
578
|
+
<div style={{ flexGrow: 1 }}>{params.value}</div>
|
|
579
|
+
{isHovered && editable && (
|
|
580
|
+
<button
|
|
581
|
+
className="edit-object-button"
|
|
582
|
+
style={{
|
|
583
|
+
position: 'absolute',
|
|
584
|
+
right: '4px',
|
|
585
|
+
background: 'transparent',
|
|
586
|
+
border: 'none',
|
|
587
|
+
cursor: 'pointer',
|
|
588
|
+
padding: '4px',
|
|
589
|
+
display: 'flex',
|
|
590
|
+
alignItems: 'center',
|
|
591
|
+
justifyContent: 'center',
|
|
592
|
+
}}
|
|
593
|
+
onClick={handleEditClick}
|
|
594
|
+
title="Upravit"
|
|
595
|
+
>
|
|
596
|
+
<span style={{ fontSize: '16px' }}>⋮</span>
|
|
597
|
+
</button>
|
|
598
|
+
)}
|
|
599
|
+
</div>
|
|
600
|
+
);
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
// Používáme funkci, která vrátí React komponentu
|
|
604
|
+
const cellRenderer = (params) => {
|
|
605
|
+
return <ObjectCellRenderer {...params} />;
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
this.#addPreparedColumn({
|
|
609
|
+
contentTooltip,
|
|
610
|
+
tooltipField,
|
|
611
|
+
tooltipInteraction,
|
|
612
|
+
tooltipShowDelay,
|
|
613
|
+
cellRenderer,
|
|
614
|
+
editable: this.#resolveEditable(editable),
|
|
615
|
+
...restProps,
|
|
616
|
+
});
|
|
617
|
+
return this;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Přidá sloupec pro zobrazení ikon s podporou badge (číselného označení).
|
|
622
|
+
* Umožňuje podmíněné zobrazování ikon a jejich stylování.
|
|
623
|
+
* @param {Object} config - Konfigurace ikonového sloupce
|
|
624
|
+
* @param {Function} [config.visibleGetter=() => true] - Funkce určující viditelnost ikony
|
|
625
|
+
* @param {string} config.cellAlign - Zarovnání ikony v buňce
|
|
626
|
+
* @param {string|Function} config.icon - Název ikony nebo funkce vracející ikonu
|
|
627
|
+
* @param {string|Function} [config.iconColor] - Barva ikony nebo funkce vracející barvu podle parametrů
|
|
628
|
+
* @param {number} [config.size=16] - Velikost ikony v pixelech
|
|
629
|
+
* @param {boolean} [config.iconLeft=false] - Zda zobrazit ikonu vlevo od textu
|
|
630
|
+
* @param {boolean} [config.iconRight=false] - Zda zobrazit ikonu vpravo od textu
|
|
631
|
+
* @param {boolean} [config.showText=true] - Zda zobrazit text (hodnotu pole)
|
|
632
|
+
* @param {number} [config.textGap=5] - Mezera mezi ikonou a textem v pixelech
|
|
633
|
+
* @param {boolean} [config.showOnGroup=false] - Zda zobrazit ikonu na skupinových řádcích
|
|
634
|
+
* @param {string|number|Function} config.badge - Text/číslo badge nebo funkce vracející badge
|
|
635
|
+
* @param {boolean} config.showZero - Zda zobrazit badge s hodnotou 0
|
|
636
|
+
* @param {string} [config.badgeColor='#dc3545'] - Barva pozadí badge
|
|
637
|
+
* @param {string} [config.badgeTextColor='white'] - Barva textu badge
|
|
638
|
+
* @param {string} [config.badgePosition='top-right'] - Pozice badge ('top-right', 'top-left', 'bottom-right', 'bottom-left')
|
|
639
|
+
* @param {Object} ...restProps - Další AG Grid vlastnosti sloupce
|
|
640
|
+
* @returns {ColumnBuilder} Instance pro chaining
|
|
641
|
+
*/
|
|
642
|
+
addIconColumn({
|
|
643
|
+
visibleGetter = () => true,
|
|
644
|
+
cellAlign,
|
|
645
|
+
icon,
|
|
646
|
+
iconColor,
|
|
647
|
+
size = 16,
|
|
648
|
+
iconLeft = false,
|
|
649
|
+
iconRight = false,
|
|
650
|
+
showText = true,
|
|
651
|
+
textGap = 5,
|
|
652
|
+
showOnGroup = false,
|
|
653
|
+
badge,
|
|
654
|
+
showZero,
|
|
655
|
+
badgeColor = '#dc3545',
|
|
656
|
+
badgeTextColor = 'white',
|
|
657
|
+
badgePosition = 'top-right',
|
|
658
|
+
...restProps
|
|
659
|
+
}) {
|
|
660
|
+
const iconRendererParams = {
|
|
661
|
+
cellAlign,
|
|
662
|
+
visibleGetter,
|
|
663
|
+
icon,
|
|
664
|
+
iconColor,
|
|
665
|
+
size,
|
|
666
|
+
iconLeft,
|
|
667
|
+
iconRight,
|
|
668
|
+
showText,
|
|
669
|
+
textGap,
|
|
670
|
+
showOnGroup,
|
|
671
|
+
badge,
|
|
672
|
+
showZero,
|
|
673
|
+
badgeColor,
|
|
674
|
+
badgeTextColor,
|
|
675
|
+
badgePosition,
|
|
676
|
+
};
|
|
677
|
+
this.#addPreparedColumn({
|
|
678
|
+
iconRenderer: true,
|
|
679
|
+
iconRendererParams,
|
|
680
|
+
...restProps,
|
|
681
|
+
});
|
|
682
|
+
return this;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Přidá sloupec pro zobrazování stavů s kruhovým pozadím.
|
|
687
|
+
* Zobrazuje text stavu v kruhovém pozadí s definovanou barvou.
|
|
688
|
+
* @param {Object} config - Konfigurace stavového sloupce
|
|
689
|
+
* @param {Function} [config.visibleGetter=() => true] - Funkce určující viditelnost
|
|
690
|
+
* @param {string} [config.cellAlign='center'] - Zarovnání v buňce
|
|
691
|
+
* @param {string|Function} [config.bgColor] - Barva pozadí nebo funkce vracející barvu podle parametrů
|
|
692
|
+
* @param {string|Function} [config.textColor='white'] - Barva textu nebo funkce vracející barvu
|
|
693
|
+
* @param {string|Function} [config.displayField] - Pole pro zobrazení textu (pokud se liší od field)
|
|
694
|
+
* @param {number} [config.minWidth=80] - Minimální šířka kruhového pozadí
|
|
695
|
+
* @param {number} [config.fontSize=12] - Velikost fontu
|
|
696
|
+
* @param {boolean} [config.showOnGroup=false] - Zda zobrazit na skupinových řádcích
|
|
697
|
+
* @param {Object} ...restProps - Další AG Grid vlastnosti sloupce
|
|
698
|
+
* @returns {ColumnBuilder} Instance pro chaining
|
|
699
|
+
*/
|
|
700
|
+
addStateColumn({
|
|
701
|
+
visibleGetter = () => true,
|
|
702
|
+
cellAlign = 'center',
|
|
703
|
+
bgColor,
|
|
704
|
+
textColor = 'white',
|
|
705
|
+
displayField,
|
|
706
|
+
minWidth = 80,
|
|
707
|
+
fontSize = 12,
|
|
708
|
+
showOnGroup = false,
|
|
709
|
+
...restProps
|
|
710
|
+
}) {
|
|
711
|
+
const stateRendererParams = {
|
|
712
|
+
visibleGetter,
|
|
713
|
+
cellAlign,
|
|
714
|
+
bgColor,
|
|
715
|
+
textColor,
|
|
716
|
+
displayField,
|
|
717
|
+
minWidth,
|
|
718
|
+
fontSize,
|
|
719
|
+
showOnGroup,
|
|
720
|
+
};
|
|
721
|
+
this.#addPreparedColumn({
|
|
722
|
+
stateRenderer: true,
|
|
723
|
+
stateRendererParams,
|
|
724
|
+
...restProps,
|
|
725
|
+
});
|
|
726
|
+
return this;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* Přidá sloupec pro zobrazení boolean hodnot pomocí ikon (zaškrtnutí/křížek).
|
|
731
|
+
* Podporuje různé ikony pro true/false stav a podmíněnou viditelnost.
|
|
732
|
+
* @param {Object} config - Konfigurace boolean sloupce
|
|
733
|
+
* @param {boolean} [config.visibleFalse=true] - Zda zobrazit ikonu pro false hodnotu
|
|
734
|
+
* @param {boolean} [config.visibleTrue=true] - Zda zobrazit ikonu pro true hodnotu
|
|
735
|
+
* @param {string} [config.cellAlign='center'] - Zarovnání ikony v buňce
|
|
736
|
+
* @param {Function} [config.visibleGetter=() => true] - Funkce určující viditelnost ikony
|
|
737
|
+
* @param {boolean} [config.defaultIcon=true] - Zda zobrazit výchozí ikonu pro undefined hodnoty
|
|
738
|
+
* @param {string} [config.defaultIconColor='#898989'] - Barva výchozí ikony
|
|
739
|
+
* @param {number} [config.size=16] - Velikost ikony v pixelech
|
|
740
|
+
* @param {string} [config.colorTrue='green'] - Barva ikony pro true hodnotu
|
|
741
|
+
* @param {string} [config.colorFalse='red'] - Barva ikony pro false hodnotu
|
|
742
|
+
* @param {boolean} [config.showOnGroup=false] - Zda zobrazit ikonu na skupinových řádcích
|
|
743
|
+
* @param {boolean} config.editable - Zda je sloupec editovatelný
|
|
744
|
+
* @param {Object} ...restProps - Další AG Grid vlastnosti sloupce
|
|
745
|
+
* @returns {ColumnBuilder} Instance pro chaining
|
|
746
|
+
*/
|
|
747
|
+
addBooleanColumn({
|
|
748
|
+
visibleFalse = true,
|
|
749
|
+
visibleTrue = true,
|
|
750
|
+
cellAlign = 'center',
|
|
751
|
+
visibleGetter = () => true,
|
|
752
|
+
defaultIcon = true,
|
|
753
|
+
defaultIconColor = '#898989',
|
|
754
|
+
size = 16,
|
|
755
|
+
colorTrue = 'green',
|
|
756
|
+
colorFalse = 'red',
|
|
757
|
+
showOnGroup = false,
|
|
758
|
+
editable,
|
|
759
|
+
...restProps
|
|
760
|
+
}) {
|
|
761
|
+
// Create a React component for boolean cell renderer
|
|
762
|
+
const BooleanCellRenderer = React.memo((params) => {
|
|
763
|
+
const { data, value } = params;
|
|
764
|
+
|
|
765
|
+
const visibleResult = visibleGetter ? visibleGetter(data) : true;
|
|
766
|
+
|
|
767
|
+
const Icon = ({ innerValue, ...iconProps }) => {
|
|
768
|
+
if (
|
|
769
|
+
innerValue === undefined ||
|
|
770
|
+
(!visibleFalse && !innerValue) ||
|
|
771
|
+
(!visibleTrue && innerValue)
|
|
772
|
+
) {
|
|
773
|
+
if (defaultIcon)
|
|
774
|
+
return <CircleHelp size={size} color={defaultIconColor} {...iconProps} />;
|
|
775
|
+
return <div />;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
if (innerValue)
|
|
779
|
+
return <Check size={size} color={colorTrue} {...iconProps} />;
|
|
780
|
+
return <X size={size} color={colorFalse} {...iconProps} />;
|
|
781
|
+
};
|
|
782
|
+
|
|
783
|
+
const showCondition = () => {
|
|
784
|
+
const newItem = (data && data._rh_plus_ag_grid_new_item) || false;
|
|
785
|
+
return !newItem && (showOnGroup || !!data) && visibleResult;
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
if (!showCondition()) return null;
|
|
789
|
+
|
|
790
|
+
return (
|
|
791
|
+
<span
|
|
792
|
+
style={{
|
|
793
|
+
width: '100%',
|
|
794
|
+
display: 'flex',
|
|
795
|
+
justifyContent: cellAlign,
|
|
796
|
+
alignItems: 'center',
|
|
797
|
+
height: '100%',
|
|
798
|
+
}}
|
|
799
|
+
>
|
|
800
|
+
<Icon
|
|
801
|
+
style={{
|
|
802
|
+
display: 'inline-block',
|
|
803
|
+
height: '100%',
|
|
804
|
+
}}
|
|
805
|
+
innerValue={value}
|
|
806
|
+
visibleTrue={visibleTrue}
|
|
807
|
+
visibleFalse={visibleFalse}
|
|
808
|
+
/>
|
|
809
|
+
</span>
|
|
810
|
+
);
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
// Use the function that returns React component
|
|
814
|
+
const cellRenderer = (params) => {
|
|
815
|
+
return <BooleanCellRenderer {...params} />;
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
this.#addPreparedColumn({
|
|
819
|
+
cellRenderer,
|
|
820
|
+
editable: this.#resolveEditable(editable),
|
|
821
|
+
...restProps,
|
|
822
|
+
});
|
|
823
|
+
return this;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Přidá připnutý akční sloupec s dropdown menu, který se zobrazuje pouze při hoveru nad řádkem.
|
|
828
|
+
* Používa pokročilou detekci hover stavu s MutationObserver pro každou instanci gridu zvlášť.
|
|
829
|
+
* Sloupec je automaticky připnut vpravo a obsahuje akční tlačítko s kontextovým menu.
|
|
830
|
+
* @param {Object} config - Konfigurace akčního sloupce
|
|
831
|
+
* @param {Array} [config.menuItems=[]] - Array položek menu s key, label, disable vlastnostmi
|
|
832
|
+
* @param {Function} config.onActionClick - Callback při kliku na položku menu (key, params, item)
|
|
833
|
+
* @param {Function} config.onBeforeShow - Async callback před zobrazením menu pro dynamické položky
|
|
834
|
+
* @param {Object} ...restProps - Další AG Grid vlastnosti sloupce
|
|
835
|
+
* @returns {ColumnBuilder} Instance pro chaining
|
|
836
|
+
*/
|
|
837
|
+
addPinnedActionButton({
|
|
838
|
+
menuItems = [],
|
|
839
|
+
onActionClick,
|
|
840
|
+
onBeforeShow,
|
|
841
|
+
...restProps
|
|
842
|
+
} = {}) {
|
|
843
|
+
const ActionDropdownRenderer = (params) => {
|
|
844
|
+
const [isRowHovered, setIsRowHovered] = React.useState(false);
|
|
845
|
+
const [isDropdownVisible, setIsDropdownVisible] = React.useState(false);
|
|
846
|
+
const [currentMenuItems, setCurrentMenuItems] = React.useState(menuItems);
|
|
847
|
+
|
|
848
|
+
const isMountedRef = React.useRef(true);
|
|
849
|
+
const rowIndexRef = React.useRef(null);
|
|
850
|
+
const observerRef = React.useRef(null);
|
|
851
|
+
const gridContainerRef = React.useRef(null);
|
|
852
|
+
const currentHoveredRowRef = React.useRef(null);
|
|
853
|
+
const mouseListenersSetupRef = React.useRef(false);
|
|
854
|
+
|
|
855
|
+
React.useEffect(() => {
|
|
856
|
+
return () => {
|
|
857
|
+
isMountedRef.current = false;
|
|
858
|
+
cleanup();
|
|
859
|
+
};
|
|
860
|
+
}, []);
|
|
861
|
+
|
|
862
|
+
// Cleanup funkce
|
|
863
|
+
const cleanup = () => {
|
|
864
|
+
if (observerRef.current) {
|
|
865
|
+
observerRef.current.disconnect();
|
|
866
|
+
observerRef.current = null;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
if (gridContainerRef.current && mouseListenersSetupRef.current) {
|
|
870
|
+
gridContainerRef.current.removeEventListener(
|
|
871
|
+
'mousemove',
|
|
872
|
+
handleMouseMove
|
|
873
|
+
);
|
|
874
|
+
gridContainerRef.current.removeEventListener(
|
|
875
|
+
'mouseleave',
|
|
876
|
+
handleMouseLeave
|
|
877
|
+
);
|
|
878
|
+
// gridContainerRef.current.removeEventListener(
|
|
879
|
+
// 'mouseenter',
|
|
880
|
+
// handleMouseEnter
|
|
881
|
+
// );
|
|
882
|
+
mouseListenersSetupRef.current = false;
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
|
|
886
|
+
// Získáme row index z params
|
|
887
|
+
React.useEffect(() => {
|
|
888
|
+
if (params.node && params.node.rowIndex !== undefined) {
|
|
889
|
+
rowIndexRef.current = params.node.rowIndex.toString();
|
|
890
|
+
} else if (params.rowIndex !== undefined) {
|
|
891
|
+
rowIndexRef.current = params.rowIndex.toString();
|
|
892
|
+
}
|
|
893
|
+
}, [params.node, params.rowIndex]);
|
|
894
|
+
|
|
895
|
+
// Mouse event handlers
|
|
896
|
+
const handleMouseMove = React.useCallback((event) => {
|
|
897
|
+
if (!isMountedRef.current) return;
|
|
898
|
+
|
|
899
|
+
const target = event.target;
|
|
900
|
+
if (!target) return;
|
|
901
|
+
|
|
902
|
+
// Najdeme nejbližší AG-Grid row element
|
|
903
|
+
let rowElement = target.closest('.ag-row');
|
|
904
|
+
|
|
905
|
+
if (rowElement) {
|
|
906
|
+
// Získáme row index z AG-Grid attributů
|
|
907
|
+
const rowIndex =
|
|
908
|
+
rowElement.getAttribute('row-index') ||
|
|
909
|
+
rowElement.getAttribute('aria-rowindex') ||
|
|
910
|
+
rowElement.dataset.rowIndex ||
|
|
911
|
+
rowElement.getAttribute('data-ag-row-index');
|
|
912
|
+
|
|
913
|
+
if (rowIndex !== null) {
|
|
914
|
+
const normalizedRowIndex = rowIndex.toString();
|
|
915
|
+
|
|
916
|
+
// KLÍČOVÁ ZMĚNA: Explicitně resetujeme předchozí řádek při změně
|
|
917
|
+
if (normalizedRowIndex !== currentHoveredRowRef.current) {
|
|
918
|
+
// Pokud jsme měli předchozí řádek, nastavíme mu hover false
|
|
919
|
+
if (currentHoveredRowRef.current !== null) {
|
|
920
|
+
notifyRowHoverChange(currentHoveredRowRef.current, false);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// Nastavíme nový řádek jako hovered
|
|
924
|
+
currentHoveredRowRef.current = normalizedRowIndex;
|
|
925
|
+
notifyRowHoverChange(normalizedRowIndex, true);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
} else {
|
|
929
|
+
// Myš není nad žádným řádkem - resetujeme všechny
|
|
930
|
+
if (currentHoveredRowRef.current !== null) {
|
|
931
|
+
notifyRowHoverChange(currentHoveredRowRef.current, false);
|
|
932
|
+
currentHoveredRowRef.current = null;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}, []);
|
|
936
|
+
|
|
937
|
+
const handleMouseLeave = React.useCallback((event) => {
|
|
938
|
+
if (!isMountedRef.current) return;
|
|
939
|
+
|
|
940
|
+
// Lepší detekce opuštění gridu
|
|
941
|
+
const relatedTarget = event.relatedTarget;
|
|
942
|
+
|
|
943
|
+
// Pokud myš opustí celý grid container NEBO jde mimo dokument
|
|
944
|
+
if (
|
|
945
|
+
gridContainerRef.current &&
|
|
946
|
+
(!relatedTarget || !gridContainerRef.current.contains(relatedTarget))
|
|
947
|
+
) {
|
|
948
|
+
if (currentHoveredRowRef.current !== null) {
|
|
949
|
+
notifyRowHoverChange(currentHoveredRowRef.current, false);
|
|
950
|
+
currentHoveredRowRef.current = null;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}, []);
|
|
954
|
+
|
|
955
|
+
// Notifikace o změně hover stavu pro tento specifický grid
|
|
956
|
+
const notifyRowHoverChange = (rowIndex, isHovered) => {
|
|
957
|
+
if (!isMountedRef.current) return;
|
|
958
|
+
|
|
959
|
+
// EXPLICITNÍ ŘÍZENÍ: Pokud nastavujeme hover false, resetujeme stav pro všechny řádky
|
|
960
|
+
if (!isHovered && rowIndexRef.current) {
|
|
961
|
+
setIsRowHovered(false);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// Pokud je toto náš řádek a nastavujeme hover true, aktualizujeme stav
|
|
965
|
+
if (isHovered && rowIndexRef.current === rowIndex) {
|
|
966
|
+
setIsRowHovered(true);
|
|
967
|
+
}
|
|
968
|
+
};
|
|
969
|
+
|
|
970
|
+
// Nastavení observer pro tento konkrétní grid
|
|
971
|
+
const setupGridObserver = React.useCallback(() => {
|
|
972
|
+
if (!params.api || observerRef.current || !isMountedRef.current) return;
|
|
973
|
+
|
|
974
|
+
// Najdeme grid container pro tento konkrétní grid instance
|
|
975
|
+
const findThisGridContainer = () => {
|
|
976
|
+
if (params.eGridCell) {
|
|
977
|
+
let current = params.eGridCell;
|
|
978
|
+
while (current && current !== document.body) {
|
|
979
|
+
if (
|
|
980
|
+
current.classList &&
|
|
981
|
+
(current.classList.contains('ag-root-wrapper') ||
|
|
982
|
+
current.classList.contains('ag-theme-alpine') ||
|
|
983
|
+
current.classList.contains('ag-theme-balham') ||
|
|
984
|
+
current.classList.contains('ag-theme-material') ||
|
|
985
|
+
current.classList.contains('ag-theme-fresh') ||
|
|
986
|
+
current.classList.contains('ag-theme-dark') ||
|
|
987
|
+
current.classList.contains('ag-theme-blue') ||
|
|
988
|
+
current.classList.contains('ag-theme-bootstrap'))
|
|
989
|
+
) {
|
|
990
|
+
return current;
|
|
991
|
+
}
|
|
992
|
+
current = current.parentElement;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
return null;
|
|
996
|
+
};
|
|
997
|
+
|
|
998
|
+
const gridContainer = findThisGridContainer();
|
|
999
|
+
if (!gridContainer) {
|
|
1000
|
+
// Zkusíme znovu za chvíli
|
|
1001
|
+
setTimeout(setupGridObserver, 100);
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
gridContainerRef.current = gridContainer;
|
|
1006
|
+
|
|
1007
|
+
// Přidáme mouse event listenery pouze pokud ještě nejsou
|
|
1008
|
+
if (!mouseListenersSetupRef.current) {
|
|
1009
|
+
gridContainer.addEventListener('mousemove', handleMouseMove, {
|
|
1010
|
+
passive: true,
|
|
1011
|
+
});
|
|
1012
|
+
gridContainer.addEventListener('mouseleave', handleMouseLeave, {
|
|
1013
|
+
passive: true,
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
// DŮLEŽITÉ: Přidáme také mouseenter pro reset při vstupu do gridu
|
|
1017
|
+
const handleMouseEnter = () => {
|
|
1018
|
+
if (isMountedRef.current) {
|
|
1019
|
+
// Reset stavu při vstupu do gridu
|
|
1020
|
+
currentHoveredRowRef.current = null;
|
|
1021
|
+
setIsRowHovered(false);
|
|
1022
|
+
}
|
|
1023
|
+
};
|
|
1024
|
+
gridContainer.addEventListener('mouseenter', handleMouseEnter, {
|
|
1025
|
+
passive: true,
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
mouseListenersSetupRef.current = true;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
// Nastavíme MutationObserver pro tento grid
|
|
1032
|
+
observerRef.current = new MutationObserver((mutations) => {
|
|
1033
|
+
if (!isMountedRef.current) return;
|
|
1034
|
+
|
|
1035
|
+
let shouldRecalculate = false;
|
|
1036
|
+
|
|
1037
|
+
mutations.forEach((mutation) => {
|
|
1038
|
+
if (mutation.type === 'childList') {
|
|
1039
|
+
const addedRows = Array.from(mutation.addedNodes).some(
|
|
1040
|
+
(node) =>
|
|
1041
|
+
node.nodeType === Node.ELEMENT_NODE &&
|
|
1042
|
+
(node.classList?.contains('ag-row') ||
|
|
1043
|
+
node.querySelector?.('.ag-row'))
|
|
1044
|
+
);
|
|
1045
|
+
|
|
1046
|
+
const removedRows = Array.from(mutation.removedNodes).some(
|
|
1047
|
+
(node) =>
|
|
1048
|
+
node.nodeType === Node.ELEMENT_NODE &&
|
|
1049
|
+
(node.classList?.contains('ag-row') ||
|
|
1050
|
+
node.querySelector?.('.ag-row'))
|
|
1051
|
+
);
|
|
1052
|
+
|
|
1053
|
+
if (addedRows || removedRows) {
|
|
1054
|
+
shouldRecalculate = true;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
if (shouldRecalculate) {
|
|
1060
|
+
// Reset hover stavu
|
|
1061
|
+
currentHoveredRowRef.current = null;
|
|
1062
|
+
setIsRowHovered(false);
|
|
1063
|
+
|
|
1064
|
+
// Znovu detekujeme aktuální pozici myši po krátké době
|
|
1065
|
+
setTimeout(() => {
|
|
1066
|
+
if (isMountedRef.current && gridContainerRef.current) {
|
|
1067
|
+
const rect = gridContainerRef.current.getBoundingClientRect();
|
|
1068
|
+
const mouseEvent = new MouseEvent('mousemove', {
|
|
1069
|
+
clientX: window.lastMouseX || rect.left + rect.width / 2,
|
|
1070
|
+
clientY: window.lastMouseY || rect.top + rect.height / 2,
|
|
1071
|
+
bubbles: true,
|
|
1072
|
+
});
|
|
1073
|
+
gridContainerRef.current.dispatchEvent(mouseEvent);
|
|
1074
|
+
}
|
|
1075
|
+
}, 100);
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
|
|
1079
|
+
// Spustíme observer na grid container
|
|
1080
|
+
observerRef.current.observe(gridContainer, {
|
|
1081
|
+
childList: true,
|
|
1082
|
+
subtree: true,
|
|
1083
|
+
attributes: false,
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
// Sledujeme pozici myši globálně pro tento observer
|
|
1087
|
+
const trackMouse = (e) => {
|
|
1088
|
+
window.lastMouseX = e.clientX;
|
|
1089
|
+
window.lastMouseY = e.clientY;
|
|
1090
|
+
};
|
|
1091
|
+
|
|
1092
|
+
document.addEventListener('mousemove', trackMouse, { passive: true });
|
|
1093
|
+
|
|
1094
|
+
// Cleanup tracking při unmount
|
|
1095
|
+
return () => {
|
|
1096
|
+
document.removeEventListener('mousemove', trackMouse);
|
|
1097
|
+
};
|
|
1098
|
+
}, [params.api, params.eGridCell, handleMouseMove, handleMouseLeave]);
|
|
1099
|
+
|
|
1100
|
+
// Spustíme setup při mount a při změně params
|
|
1101
|
+
React.useEffect(() => {
|
|
1102
|
+
setupGridObserver();
|
|
1103
|
+
}, [setupGridObserver]);
|
|
1104
|
+
|
|
1105
|
+
const handleVisibleChange = React.useCallback(
|
|
1106
|
+
async (visible) => {
|
|
1107
|
+
if (!isMountedRef.current) return;
|
|
1108
|
+
|
|
1109
|
+
if (visible && onBeforeShow) {
|
|
1110
|
+
try {
|
|
1111
|
+
const updatedMenuItems = await onBeforeShow(params, menuItems);
|
|
1112
|
+
if (
|
|
1113
|
+
updatedMenuItems &&
|
|
1114
|
+
Array.isArray(updatedMenuItems) &&
|
|
1115
|
+
isMountedRef.current
|
|
1116
|
+
) {
|
|
1117
|
+
setCurrentMenuItems(updatedMenuItems);
|
|
1118
|
+
}
|
|
1119
|
+
} catch (error) {
|
|
1120
|
+
// Removed console.error for production
|
|
1121
|
+
if (isMountedRef.current) {
|
|
1122
|
+
setCurrentMenuItems(menuItems);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
if (isMountedRef.current) {
|
|
1128
|
+
setIsDropdownVisible(visible);
|
|
1129
|
+
}
|
|
1130
|
+
},
|
|
1131
|
+
[params, menuItems, onBeforeShow]
|
|
1132
|
+
);
|
|
1133
|
+
|
|
1134
|
+
React.useEffect(() => {
|
|
1135
|
+
if (isMountedRef.current) {
|
|
1136
|
+
setCurrentMenuItems(menuItems);
|
|
1137
|
+
}
|
|
1138
|
+
}, [menuItems]);
|
|
1139
|
+
|
|
1140
|
+
const menu = React.useMemo(
|
|
1141
|
+
() => (
|
|
1142
|
+
<Menu
|
|
1143
|
+
onClick={(e) => {
|
|
1144
|
+
if (onActionClick) {
|
|
1145
|
+
const item = currentMenuItems.filter(f => f.key === e.key)[0];
|
|
1146
|
+
onActionClick(e.key, params, item);
|
|
1147
|
+
}
|
|
1148
|
+
setIsDropdownVisible(false);
|
|
1149
|
+
}}
|
|
1150
|
+
>
|
|
1151
|
+
{currentMenuItems.map((item) => {
|
|
1152
|
+
if (item.type === 'divider') {
|
|
1153
|
+
return <Divider key={item.key} style={{ margin: '4px 0' }} />;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
let isDisabled = false;
|
|
1157
|
+
if (typeof item.disable === 'function') {
|
|
1158
|
+
isDisabled = item.disable(params);
|
|
1159
|
+
} else if (typeof item.disable === 'boolean') {
|
|
1160
|
+
isDisabled = item.disable;
|
|
1161
|
+
} else if (item.disabled !== undefined) {
|
|
1162
|
+
isDisabled = item.disabled;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
return (
|
|
1166
|
+
<Menu.Item key={item.key} disabled={isDisabled}>
|
|
1167
|
+
{item.label}
|
|
1168
|
+
</Menu.Item>
|
|
1169
|
+
);
|
|
1170
|
+
})}
|
|
1171
|
+
</Menu>
|
|
1172
|
+
),
|
|
1173
|
+
[currentMenuItems, onActionClick, params]
|
|
1174
|
+
);
|
|
1175
|
+
|
|
1176
|
+
const containerStyle = {
|
|
1177
|
+
width: '32px',
|
|
1178
|
+
height: '32px',
|
|
1179
|
+
display: 'flex',
|
|
1180
|
+
alignItems: 'center',
|
|
1181
|
+
justifyContent: 'center',
|
|
1182
|
+
position: 'relative',
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1185
|
+
const buttonStyle = {
|
|
1186
|
+
minWidth: 'auto',
|
|
1187
|
+
width: '32px',
|
|
1188
|
+
height: '32px',
|
|
1189
|
+
padding: '0',
|
|
1190
|
+
background: 'transparent',
|
|
1191
|
+
border: 'none',
|
|
1192
|
+
cursor: 'pointer',
|
|
1193
|
+
display: 'flex',
|
|
1194
|
+
alignItems: 'center',
|
|
1195
|
+
justifyContent: 'center',
|
|
1196
|
+
opacity: isRowHovered || isDropdownVisible ? 1 : 0,
|
|
1197
|
+
visibility: isRowHovered || isDropdownVisible ? 'visible' : 'hidden',
|
|
1198
|
+
transition: 'opacity 0.15s ease-in-out, visibility 0.15s ease-in-out',
|
|
1199
|
+
pointerEvents: isRowHovered || isDropdownVisible ? 'auto' : 'none',
|
|
1200
|
+
};
|
|
1201
|
+
|
|
1202
|
+
return (
|
|
1203
|
+
<div style={containerStyle}>
|
|
1204
|
+
<Dropdown
|
|
1205
|
+
overlayStyle={{ zIndex: 5000 }}
|
|
1206
|
+
overlay={menu}
|
|
1207
|
+
trigger={['click']}
|
|
1208
|
+
visible={isDropdownVisible}
|
|
1209
|
+
onVisibleChange={handleVisibleChange}
|
|
1210
|
+
getPopupContainer={() => document.body}
|
|
1211
|
+
>
|
|
1212
|
+
<div
|
|
1213
|
+
style={buttonStyle}
|
|
1214
|
+
onClick={(e) => {
|
|
1215
|
+
e.stopPropagation();
|
|
1216
|
+
}}
|
|
1217
|
+
>
|
|
1218
|
+
<ActionIcon />
|
|
1219
|
+
</div>
|
|
1220
|
+
</Dropdown>
|
|
1221
|
+
</div>
|
|
1222
|
+
);
|
|
1223
|
+
};
|
|
1224
|
+
|
|
1225
|
+
this.#addPreparedColumn({
|
|
1226
|
+
headerName: '',
|
|
1227
|
+
pinned: 'right',
|
|
1228
|
+
maxWidth: 40,
|
|
1229
|
+
minWidth: 40,
|
|
1230
|
+
suppressSizeToFit: true,
|
|
1231
|
+
suppressMenu: true,
|
|
1232
|
+
sortable: false,
|
|
1233
|
+
filter: false,
|
|
1234
|
+
resizable: false,
|
|
1235
|
+
cellRenderer: ActionDropdownRenderer,
|
|
1236
|
+
cellClass: 'action-button-cell-observer',
|
|
1237
|
+
...restProps,
|
|
1238
|
+
});
|
|
1239
|
+
|
|
1240
|
+
return this;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* Přidá sloupec s custom tlačítky s podmíněnou viditelností.
|
|
1245
|
+
* Každé tlačítko může mít vlastní styl, akci a podmínku viditelnosti.
|
|
1246
|
+
* @param {Object} config - Konfigurace tlačítkového sloupce
|
|
1247
|
+
* @param {Array} config.buttons - Array definic tlačítek s vlastnostmi jako text, onClick, style
|
|
1248
|
+
* @param {Function} [config.visibleGetter=() => true] - Funkce určující viditelnost tlačítek
|
|
1249
|
+
* @param {boolean} config.editable - Zda je sloupec editovatelný
|
|
1250
|
+
* @param {Object} ...restProps - Další AG Grid vlastnosti sloupce
|
|
1251
|
+
* @returns {ColumnBuilder} Instance pro chaining
|
|
1252
|
+
*/
|
|
1253
|
+
addButtonColumn({
|
|
1254
|
+
buttons,
|
|
1255
|
+
visibleGetter = () => true,
|
|
1256
|
+
editable,
|
|
1257
|
+
...restProps
|
|
1258
|
+
}) {
|
|
1259
|
+
const buttonRendererParams = {
|
|
1260
|
+
buttons,
|
|
1261
|
+
visibleGetter,
|
|
1262
|
+
};
|
|
1263
|
+
this.#addPreparedColumn({
|
|
1264
|
+
buttonRenderer: true,
|
|
1265
|
+
buttonRendererParams,
|
|
1266
|
+
editable: this.#resolveEditable(editable),
|
|
1267
|
+
...restProps,
|
|
1268
|
+
});
|
|
1269
|
+
return this;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
/**
|
|
1273
|
+
* Privátní pomocná metoda pro správné nastavení editable vlastnosti sloupce.
|
|
1274
|
+
* Zajišťuje konzistentní zpracování boolean hodnot pro editovatelnost.
|
|
1275
|
+
* @param {boolean|Function} editable - Editovatelnost sloupce nebo funkce vracející boolean
|
|
1276
|
+
* @returns {boolean|Function} Upravená hodnota editovatelnosti
|
|
1277
|
+
*/
|
|
1278
|
+
#resolveEditable(editable) {
|
|
1279
|
+
if (!editable) return false;
|
|
1280
|
+
return editable;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
/**
|
|
1284
|
+
* Finální metoda pro sestavení pole sloupců AG Grid.
|
|
1285
|
+
* Vrací kompletní konfiguraci všech přidaných sloupců připravených pro AG Grid.
|
|
1286
|
+
* @returns {Array} Array připravených definic sloupců pro AG Grid
|
|
1287
|
+
*/
|
|
1288
|
+
build() {
|
|
1289
|
+
return this.columns;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
export default ColumnBuilder;
|
|
1280
1294
|
/* eslint-enable */
|