@addsign/moje-agenda-shared-lib 2.0.70 → 2.0.72
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/dist/assets/style.css +13 -0
- package/dist/components/datatable/DataTableServer.d.ts +14 -1
- package/dist/components/datatable/DataTableServer.js +28 -5
- package/dist/components/datatable/DataTableServer.js.map +1 -1
- package/lib/components/datatable/DataTableServer.tsx +1399 -1364
- package/package.json +1 -1
|
@@ -1,1364 +1,1399 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
useCallback,
|
|
3
|
-
useEffect,
|
|
4
|
-
useMemo,
|
|
5
|
-
useRef,
|
|
6
|
-
useState,
|
|
7
|
-
} from "react";
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
Button,
|
|
11
|
-
DataTableColumn,
|
|
12
|
-
DateField,
|
|
13
|
-
DateRangeField,
|
|
14
|
-
FormField,
|
|
15
|
-
IOptionItem,
|
|
16
|
-
Spinner,
|
|
17
|
-
handleErrors,
|
|
18
|
-
useFederationContext,
|
|
19
|
-
} from "../../main";
|
|
20
|
-
import {
|
|
21
|
-
MdArrowBack,
|
|
22
|
-
MdArrowDownward,
|
|
23
|
-
MdArrowForward,
|
|
24
|
-
MdArrowUpward,
|
|
25
|
-
MdClose,
|
|
26
|
-
MdOutlineFilterAlt,
|
|
27
|
-
MdOutlineFilterAltOff,
|
|
28
|
-
MdOutlineUnfoldMore,
|
|
29
|
-
MdSearch,
|
|
30
|
-
} from "react-icons/md";
|
|
31
|
-
import { Input } from "../ui/input";
|
|
32
|
-
import { Resizable } from "./Resizable";
|
|
33
|
-
import { DatatableSettings } from "./DatatableSettings";
|
|
34
|
-
import { MultiSelect } from "../ui/multi-select";
|
|
35
|
-
import {
|
|
36
|
-
Select,
|
|
37
|
-
SelectContent,
|
|
38
|
-
SelectItem,
|
|
39
|
-
SelectTrigger,
|
|
40
|
-
SelectValue,
|
|
41
|
-
} from "../ui/select";
|
|
42
|
-
|
|
43
|
-
import * as XLSX from "xlsx";
|
|
44
|
-
|
|
45
|
-
interface ISortConfig {
|
|
46
|
-
sortParam: string;
|
|
47
|
-
direction: "asc" | "desc" | null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
interface DataTableServerProps<T> {
|
|
51
|
-
id: string;
|
|
52
|
-
url: string;
|
|
53
|
-
columns: DataTableColumn<T | "actions">[];
|
|
54
|
-
title?: string;
|
|
55
|
-
subtitle?: string;
|
|
56
|
-
allowSearch?: boolean;
|
|
57
|
-
showHeader?: boolean;
|
|
58
|
-
rowAction?: (item: T) => void;
|
|
59
|
-
// bulkActions?: BulkAction<T>[];
|
|
60
|
-
bulkAction?: (items: T[]) => JSX.Element;
|
|
61
|
-
filters?: object;
|
|
62
|
-
selectedItemKey?: string;
|
|
63
|
-
itemsPerPageOptions?: IOptionItem[];
|
|
64
|
-
setMinWidth?: boolean;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
{ value:
|
|
69
|
-
{ value:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
parsedObject
|
|
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
|
-
const
|
|
128
|
-
const
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
const [
|
|
134
|
-
const
|
|
135
|
-
const [
|
|
136
|
-
const [
|
|
137
|
-
|
|
138
|
-
const [
|
|
139
|
-
|
|
140
|
-
const [
|
|
141
|
-
|
|
142
|
-
const [
|
|
143
|
-
const [
|
|
144
|
-
const [
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const
|
|
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
|
-
|
|
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
|
-
column.
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
newFilterOptions[column.filterParam as string] =
|
|
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
|
-
|
|
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
|
-
storageObject.
|
|
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
|
-
if (
|
|
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
|
-
const
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
if (
|
|
739
|
-
column.
|
|
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
|
-
const
|
|
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
|
-
|
|
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
|
-
<div className="absolute inset-0 flex items-center justify-center
|
|
946
|
-
|
|
947
|
-
</div>
|
|
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
|
-
value
|
|
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
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
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
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1
|
+
import React, {
|
|
2
|
+
useCallback,
|
|
3
|
+
useEffect,
|
|
4
|
+
useMemo,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from "react";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
Button,
|
|
11
|
+
DataTableColumn,
|
|
12
|
+
DateField,
|
|
13
|
+
DateRangeField,
|
|
14
|
+
FormField,
|
|
15
|
+
IOptionItem,
|
|
16
|
+
Spinner,
|
|
17
|
+
handleErrors,
|
|
18
|
+
useFederationContext,
|
|
19
|
+
} from "../../main";
|
|
20
|
+
import {
|
|
21
|
+
MdArrowBack,
|
|
22
|
+
MdArrowDownward,
|
|
23
|
+
MdArrowForward,
|
|
24
|
+
MdArrowUpward,
|
|
25
|
+
MdClose,
|
|
26
|
+
MdOutlineFilterAlt,
|
|
27
|
+
MdOutlineFilterAltOff,
|
|
28
|
+
MdOutlineUnfoldMore,
|
|
29
|
+
MdSearch,
|
|
30
|
+
} from "react-icons/md";
|
|
31
|
+
import { Input } from "../ui/input";
|
|
32
|
+
import { Resizable } from "./Resizable";
|
|
33
|
+
import { DatatableSettings } from "./DatatableSettings";
|
|
34
|
+
import { MultiSelect } from "../ui/multi-select";
|
|
35
|
+
import {
|
|
36
|
+
Select,
|
|
37
|
+
SelectContent,
|
|
38
|
+
SelectItem,
|
|
39
|
+
SelectTrigger,
|
|
40
|
+
SelectValue,
|
|
41
|
+
} from "../ui/select";
|
|
42
|
+
|
|
43
|
+
import * as XLSX from "xlsx";
|
|
44
|
+
|
|
45
|
+
interface ISortConfig {
|
|
46
|
+
sortParam: string;
|
|
47
|
+
direction: "asc" | "desc" | null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface DataTableServerProps<T> {
|
|
51
|
+
id: string;
|
|
52
|
+
url: string;
|
|
53
|
+
columns: DataTableColumn<T | "actions">[];
|
|
54
|
+
title?: string;
|
|
55
|
+
subtitle?: string;
|
|
56
|
+
allowSearch?: boolean;
|
|
57
|
+
showHeader?: boolean;
|
|
58
|
+
rowAction?: (item: T) => void;
|
|
59
|
+
// bulkActions?: BulkAction<T>[];
|
|
60
|
+
bulkAction?: (items: T[]) => JSX.Element;
|
|
61
|
+
filters?: object;
|
|
62
|
+
selectedItemKey?: string;
|
|
63
|
+
itemsPerPageOptions?: IOptionItem[];
|
|
64
|
+
setMinWidth?: boolean;
|
|
65
|
+
onDataLoaded?: (data: IPageable<T>) => void;
|
|
66
|
+
}
|
|
67
|
+
const defaultItemsPerPageOptions: IOptionItem[] = [
|
|
68
|
+
{ value: 10, label: "10" },
|
|
69
|
+
{ value: 50, label: "50" },
|
|
70
|
+
{ value: 100, label: "100" },
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
type DataTableInternalItems = {
|
|
74
|
+
_isHighlighted?: boolean;
|
|
75
|
+
id: string; // Assuming items have an `id` field for identification
|
|
76
|
+
};
|
|
77
|
+
interface DataTableStorageObject {
|
|
78
|
+
columnFilters: Record<string, string>;
|
|
79
|
+
showColFilters: boolean;
|
|
80
|
+
currentPage: number;
|
|
81
|
+
itemsPerPage: number;
|
|
82
|
+
sortConfig: ISortConfig | null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const resetAllDataTablePaging = () => {
|
|
86
|
+
Object.keys(localStorage)
|
|
87
|
+
.filter((key) => key.startsWith("datatable:"))
|
|
88
|
+
.forEach((key) => {
|
|
89
|
+
const storageObject = localStorage.getItem(key);
|
|
90
|
+
if (storageObject) {
|
|
91
|
+
const parsedObject: DataTableStorageObject = JSON.parse(storageObject);
|
|
92
|
+
parsedObject.currentPage = 0;
|
|
93
|
+
localStorage.setItem(key, JSON.stringify(parsedObject));
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
interface IPageable<T> {
|
|
99
|
+
content: T[];
|
|
100
|
+
empty: boolean;
|
|
101
|
+
first: boolean;
|
|
102
|
+
last: boolean;
|
|
103
|
+
number: number;
|
|
104
|
+
numberOfElements: number;
|
|
105
|
+
size: number;
|
|
106
|
+
totalElements: number;
|
|
107
|
+
totalPages: number;
|
|
108
|
+
isPageable?: boolean;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function DataTableServer<T extends DataTableInternalItems>({
|
|
112
|
+
id,
|
|
113
|
+
url,
|
|
114
|
+
columns,
|
|
115
|
+
title,
|
|
116
|
+
subtitle,
|
|
117
|
+
allowSearch = false,
|
|
118
|
+
showHeader = true,
|
|
119
|
+
rowAction,
|
|
120
|
+
bulkAction,
|
|
121
|
+
filters,
|
|
122
|
+
selectedItemKey = "id",
|
|
123
|
+
itemsPerPageOptions = defaultItemsPerPageOptions,
|
|
124
|
+
setMinWidth = false,
|
|
125
|
+
onDataLoaded,
|
|
126
|
+
}: DataTableServerProps<T>) {
|
|
127
|
+
const abortControllerRef = useRef<AbortController | null>(null);
|
|
128
|
+
const topScrollbarRef = useRef<HTMLDivElement | null>(null);
|
|
129
|
+
const bottomScrollbarRef = useRef<HTMLDivElement | null>(null);
|
|
130
|
+
const tableRef = useRef<HTMLTableElement | null>(null);
|
|
131
|
+
const syncWidthRef = useRef<HTMLDivElement | null>(null);
|
|
132
|
+
|
|
133
|
+
const [itemsPerPageLocal, setItemsPerPageLocal] = useState<number>(10);
|
|
134
|
+
const federationContext = useFederationContext();
|
|
135
|
+
const [data, setData] = useState<IPageable<T>>();
|
|
136
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
137
|
+
const [isLocalStorageLoaded, setIsLocalStorageLoaded] = useState(false);
|
|
138
|
+
const [tableKey, setTableKey] = useState(0);
|
|
139
|
+
|
|
140
|
+
const [hasMounted, setHasMounted] = useState(false);
|
|
141
|
+
|
|
142
|
+
const [currentPage, setCurrentPage] = useState<number>(0);
|
|
143
|
+
const [selectedItems, setSelectedItems] = useState<T[]>([]);
|
|
144
|
+
const [fulltextSearch, setFulltextSearch] = useState("");
|
|
145
|
+
const [filterOptions, setFilterOptions] = useState<Record<string, any[]>>({});
|
|
146
|
+
const [columnFilters, setColumnFilters] = useState<{ [key: string]: any }>(
|
|
147
|
+
{}
|
|
148
|
+
);
|
|
149
|
+
const [showColFilters, setShowColFilters] = useState<boolean>(false);
|
|
150
|
+
const [sortConfig, setSortConfig] = useState<ISortConfig | null>(null);
|
|
151
|
+
const prevDepsRef = useRef<any[]>([]);
|
|
152
|
+
const prevFilterDepsRef = useRef<any[]>([]);
|
|
153
|
+
|
|
154
|
+
const createDataPageable = (
|
|
155
|
+
response: any,
|
|
156
|
+
itemsPerPage: number
|
|
157
|
+
): IPageable<T> => {
|
|
158
|
+
const isPageable = !!response.data?.content;
|
|
159
|
+
return {
|
|
160
|
+
content: response.data.content || response.data,
|
|
161
|
+
empty: isPageable ? response.data.empty : true,
|
|
162
|
+
first: isPageable ? response.data.first : true,
|
|
163
|
+
last: isPageable ? response.data.last : true,
|
|
164
|
+
number: isPageable ? response.data.number : 0,
|
|
165
|
+
numberOfElements: response.data.numberOfElements || response.data.length,
|
|
166
|
+
size: response.data?.size || itemsPerPage,
|
|
167
|
+
totalElements: response.data?.totalElements || response.data.length,
|
|
168
|
+
totalPages: response.data?.totalPages || 1,
|
|
169
|
+
isPageable: isPageable,
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const [reloadData, setReloadData] = useState(false);
|
|
174
|
+
|
|
175
|
+
const mergedFilters: { [key: string]: any } = useMemo(() => {
|
|
176
|
+
return showColFilters ? { ...columnFilters, ...filters } : filters || {};
|
|
177
|
+
}, [columnFilters, filters, showColFilters]);
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
const currentDeps = [
|
|
180
|
+
url,
|
|
181
|
+
showColFilters,
|
|
182
|
+
columnFilters,
|
|
183
|
+
itemsPerPageLocal,
|
|
184
|
+
currentPage,
|
|
185
|
+
sortConfig,
|
|
186
|
+
filters,
|
|
187
|
+
tableKey,
|
|
188
|
+
];
|
|
189
|
+
|
|
190
|
+
// Kontrola, jestli se skutečně něco změnilo
|
|
191
|
+
const hasChanged = currentDeps.some((dep, index) => {
|
|
192
|
+
return JSON.stringify(dep) !== JSON.stringify(prevDepsRef.current[index]);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
if (hasChanged) {
|
|
196
|
+
console.log(
|
|
197
|
+
"setting reloadData - actual change detected",
|
|
198
|
+
url,
|
|
199
|
+
showColFilters,
|
|
200
|
+
columnFilters,
|
|
201
|
+
itemsPerPageLocal,
|
|
202
|
+
currentPage,
|
|
203
|
+
sortConfig,
|
|
204
|
+
filters,
|
|
205
|
+
tableKey,
|
|
206
|
+
reloadData
|
|
207
|
+
);
|
|
208
|
+
setReloadData(true);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
prevDepsRef.current = currentDeps;
|
|
212
|
+
}, [
|
|
213
|
+
url,
|
|
214
|
+
showColFilters,
|
|
215
|
+
columnFilters,
|
|
216
|
+
itemsPerPageLocal,
|
|
217
|
+
currentPage,
|
|
218
|
+
sortConfig,
|
|
219
|
+
filters,
|
|
220
|
+
tableKey,
|
|
221
|
+
]);
|
|
222
|
+
|
|
223
|
+
useEffect(() => {
|
|
224
|
+
console.log("reloadData", reloadData);
|
|
225
|
+
if (reloadData) {
|
|
226
|
+
if (abortControllerRef.current) {
|
|
227
|
+
abortControllerRef.current.abort();
|
|
228
|
+
}
|
|
229
|
+
// Create a new AbortController for the new request
|
|
230
|
+
abortControllerRef.current = new AbortController();
|
|
231
|
+
const currentAbortController = abortControllerRef.current;
|
|
232
|
+
// load data from API
|
|
233
|
+
|
|
234
|
+
if (currentPage === undefined) return;
|
|
235
|
+
setIsLoading(true);
|
|
236
|
+
|
|
237
|
+
//odebrani prazdny filteru a transformace multi-select hodnot
|
|
238
|
+
const filteredMergedFilters = Object.entries(mergedFilters).reduce(
|
|
239
|
+
(acc: Record<string, any>, [key, value]) => {
|
|
240
|
+
// Skip null and empty string values
|
|
241
|
+
if (value === null || value === "") {
|
|
242
|
+
return acc;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Handle multi-select values (arrays)
|
|
246
|
+
if (Array.isArray(value)) {
|
|
247
|
+
if (value.length > 0) {
|
|
248
|
+
acc[key] = value.join(",");
|
|
249
|
+
}
|
|
250
|
+
return acc;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Handle other values
|
|
254
|
+
acc[key] = value;
|
|
255
|
+
return acc;
|
|
256
|
+
},
|
|
257
|
+
{}
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
federationContext.apiClient
|
|
261
|
+
.get(url, {
|
|
262
|
+
signal: currentAbortController.signal,
|
|
263
|
+
params: {
|
|
264
|
+
...filteredMergedFilters,
|
|
265
|
+
pageSize: itemsPerPageLocal,
|
|
266
|
+
page: currentPage,
|
|
267
|
+
sortBy: sortConfig?.sortParam,
|
|
268
|
+
sortDirection: sortConfig?.direction,
|
|
269
|
+
},
|
|
270
|
+
})
|
|
271
|
+
.then((response) => {
|
|
272
|
+
const dataPageable: IPageable<T> = createDataPageable(
|
|
273
|
+
response,
|
|
274
|
+
itemsPerPageLocal || 10
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
setData(dataPageable);
|
|
278
|
+
// setData(response.data);
|
|
279
|
+
setIsLoading(false);
|
|
280
|
+
onDataLoaded?.(dataPageable);
|
|
281
|
+
})
|
|
282
|
+
.catch((error) => {
|
|
283
|
+
if (error.code === "ERR_CANCELED") {
|
|
284
|
+
console.log("Request was aborted");
|
|
285
|
+
} else {
|
|
286
|
+
console.error("Error fetching data:", error);
|
|
287
|
+
handleErrors(error, federationContext.emitter);
|
|
288
|
+
const emptyDataPageable: IPageable<T> = {
|
|
289
|
+
content: [],
|
|
290
|
+
empty: true,
|
|
291
|
+
first: true,
|
|
292
|
+
last: true,
|
|
293
|
+
number: 0,
|
|
294
|
+
numberOfElements: 0,
|
|
295
|
+
size: itemsPerPageLocal || 10,
|
|
296
|
+
totalElements: 0,
|
|
297
|
+
totalPages: 1,
|
|
298
|
+
};
|
|
299
|
+
setData(emptyDataPageable);
|
|
300
|
+
setIsLoading(false);
|
|
301
|
+
onDataLoaded?.(emptyDataPageable);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
setReloadData(false);
|
|
306
|
+
}
|
|
307
|
+
}, [reloadData]);
|
|
308
|
+
// nastaveni currentPage u jinych datatable na 0
|
|
309
|
+
useEffect(() => {
|
|
310
|
+
Object.keys(localStorage)
|
|
311
|
+
.filter(
|
|
312
|
+
(key) => key.startsWith("datatable:") && key !== `datatable:${id}`
|
|
313
|
+
)
|
|
314
|
+
.forEach((key) => {
|
|
315
|
+
const storageObject = localStorage.getItem(key);
|
|
316
|
+
if (storageObject) {
|
|
317
|
+
const parsedObject: DataTableStorageObject =
|
|
318
|
+
JSON.parse(storageObject);
|
|
319
|
+
parsedObject.currentPage = 0;
|
|
320
|
+
localStorage.setItem(key, JSON.stringify(parsedObject));
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
}, [id]);
|
|
324
|
+
|
|
325
|
+
//load from localstorage
|
|
326
|
+
useEffect(() => {
|
|
327
|
+
if (id) {
|
|
328
|
+
const storageKey = `datatable:${id}`;
|
|
329
|
+
|
|
330
|
+
const storedStorageObject = localStorage.getItem(storageKey);
|
|
331
|
+
if (storedStorageObject) {
|
|
332
|
+
const storageObject: DataTableStorageObject =
|
|
333
|
+
JSON.parse(storedStorageObject);
|
|
334
|
+
setColumnFilters(storageObject.columnFilters);
|
|
335
|
+
setShowColFilters(storageObject.showColFilters);
|
|
336
|
+
setCurrentPage(storageObject.currentPage || 0);
|
|
337
|
+
setSortConfig(storageObject.sortConfig || null);
|
|
338
|
+
|
|
339
|
+
setItemsPerPageLocal(storageObject.itemsPerPage || 10);
|
|
340
|
+
}
|
|
341
|
+
setIsLocalStorageLoaded(true);
|
|
342
|
+
}
|
|
343
|
+
}, [id]);
|
|
344
|
+
|
|
345
|
+
useEffect(() => {
|
|
346
|
+
const currentFilterDeps = [columns, federationContext.apiClient];
|
|
347
|
+
|
|
348
|
+
// Kontrola, jestli se skutečně něco změnilo
|
|
349
|
+
const hasFilterChanged = currentFilterDeps.some((dep, index) => {
|
|
350
|
+
const prev = prevFilterDepsRef.current[index];
|
|
351
|
+
if (index === 1) {
|
|
352
|
+
// federationContext.apiClient (index 1) - referenční porovnání
|
|
353
|
+
return dep !== prev;
|
|
354
|
+
} else {
|
|
355
|
+
// columns (index 0) - deep porovnání
|
|
356
|
+
return JSON.stringify(dep) !== JSON.stringify(prev);
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
if (hasFilterChanged) {
|
|
361
|
+
const fetchFilterOptions = async (column: DataTableColumn<T>) => {
|
|
362
|
+
if (column.filterOptions) {
|
|
363
|
+
return column.filterOptions;
|
|
364
|
+
} else if (column.filterSource) {
|
|
365
|
+
try {
|
|
366
|
+
const response = await federationContext.apiClient.get(
|
|
367
|
+
column.filterSource
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
const options: IOptionItem[] = [];
|
|
371
|
+
|
|
372
|
+
response.data.forEach((item: any) => {
|
|
373
|
+
const categoryId =
|
|
374
|
+
item[column.filterValueKey as keyof typeof item]?.toString();
|
|
375
|
+
const categoryLabel =
|
|
376
|
+
item[column.filterLabelKey as keyof typeof item]?.toString();
|
|
377
|
+
const subcategories = item.subcategories;
|
|
378
|
+
|
|
379
|
+
if (
|
|
380
|
+
Array.isArray(subcategories) &&
|
|
381
|
+
subcategories.length > 0 &&
|
|
382
|
+
column.filterParam2
|
|
383
|
+
) {
|
|
384
|
+
//add parent categoriz without subcategiries
|
|
385
|
+
options.push({
|
|
386
|
+
value: categoryId,
|
|
387
|
+
label: categoryLabel,
|
|
388
|
+
});
|
|
389
|
+
// Multiply options by subcategories
|
|
390
|
+
subcategories.forEach((subcategory: any) => {
|
|
391
|
+
const subcategoryId = subcategory.id?.toString();
|
|
392
|
+
const subcategoryLabel = subcategory.name?.toString();
|
|
393
|
+
|
|
394
|
+
if (subcategoryId && subcategoryLabel) {
|
|
395
|
+
options.push({
|
|
396
|
+
value: `${categoryId}-${subcategoryId}`,
|
|
397
|
+
label: `${categoryLabel} - ${subcategoryLabel}`,
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
} else {
|
|
402
|
+
// No subcategories, use category only
|
|
403
|
+
options.push({
|
|
404
|
+
value: categoryId,
|
|
405
|
+
label: categoryLabel,
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
return options;
|
|
411
|
+
} catch (error) {
|
|
412
|
+
console.error("Error fetching filter options:", error);
|
|
413
|
+
return [];
|
|
414
|
+
}
|
|
415
|
+
} else {
|
|
416
|
+
return [];
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
const updateFilterOptions = async () => {
|
|
421
|
+
const newFilterOptions: Record<string, any[]> = {};
|
|
422
|
+
|
|
423
|
+
for (const column of columns) {
|
|
424
|
+
if (
|
|
425
|
+
(column.filterType === "select" ||
|
|
426
|
+
column.filterType === "multi-select") &&
|
|
427
|
+
(column.filterSource || column.filterOptions) &&
|
|
428
|
+
column.filterValueKey &&
|
|
429
|
+
column.filterLabelKey &&
|
|
430
|
+
column.filterParam
|
|
431
|
+
) {
|
|
432
|
+
const options = await fetchFilterOptions(column);
|
|
433
|
+
|
|
434
|
+
if (options && column.filterType === "select") {
|
|
435
|
+
// Filter out empty values and add a "clear" option
|
|
436
|
+
const filteredOptions = options.filter(
|
|
437
|
+
(option: IOptionItem) =>
|
|
438
|
+
option.value !== null &&
|
|
439
|
+
option.value !== undefined &&
|
|
440
|
+
option.value !== ""
|
|
441
|
+
);
|
|
442
|
+
newFilterOptions[column.filterParam as string] = [
|
|
443
|
+
{ value: "__clear__", label: "Všechny" },
|
|
444
|
+
...filteredOptions,
|
|
445
|
+
];
|
|
446
|
+
} else if (options && column.filterType === "multi-select") {
|
|
447
|
+
newFilterOptions[column.filterParam as string] = options;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
setFilterOptions(newFilterOptions);
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
console.log(
|
|
456
|
+
"updateFilterOptions - actual change detected",
|
|
457
|
+
columns,
|
|
458
|
+
federationContext.apiClient
|
|
459
|
+
);
|
|
460
|
+
updateFilterOptions();
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
prevFilterDepsRef.current = currentFilterDeps;
|
|
464
|
+
}, [columns, federationContext.apiClient]);
|
|
465
|
+
|
|
466
|
+
const hasSomeColFilters = useMemo(() => {
|
|
467
|
+
return columns.some((column) => !!column.filterParam);
|
|
468
|
+
}, [columns]);
|
|
469
|
+
|
|
470
|
+
const requestSort = (sortParam: string) => {
|
|
471
|
+
setSortConfig((prevSortConfig) => {
|
|
472
|
+
if (
|
|
473
|
+
prevSortConfig?.sortParam === sortParam &&
|
|
474
|
+
prevSortConfig.direction !== null
|
|
475
|
+
) {
|
|
476
|
+
return prevSortConfig.direction === "asc"
|
|
477
|
+
? { sortParam, direction: "desc" }
|
|
478
|
+
: null;
|
|
479
|
+
} else {
|
|
480
|
+
return { sortParam, direction: "asc" };
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
const getSortIcon = (sortParam: string) => {
|
|
486
|
+
if (sortConfig?.sortParam === sortParam) {
|
|
487
|
+
return sortConfig.direction === "asc" ? (
|
|
488
|
+
<MdArrowUpward fontSize="small" />
|
|
489
|
+
) : sortConfig.direction === "desc" ? (
|
|
490
|
+
<MdArrowDownward fontSize="small" />
|
|
491
|
+
) : (
|
|
492
|
+
<MdOutlineUnfoldMore fontSize="small" className=" " />
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
return <MdOutlineUnfoldMore fontSize="small" className=" " />;
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
const handleSelectItem = (item: T) => {
|
|
499
|
+
setSelectedItems((prevSelectedItems) => {
|
|
500
|
+
if (
|
|
501
|
+
prevSelectedItems.find(
|
|
502
|
+
(selectedItem) =>
|
|
503
|
+
selectedItem[selectedItemKey as keyof T] ===
|
|
504
|
+
item[selectedItemKey as keyof T]
|
|
505
|
+
)
|
|
506
|
+
) {
|
|
507
|
+
return prevSelectedItems.filter(
|
|
508
|
+
(selectedItem) =>
|
|
509
|
+
selectedItem[selectedItemKey as keyof T] !==
|
|
510
|
+
item[selectedItemKey as keyof T]
|
|
511
|
+
);
|
|
512
|
+
} else {
|
|
513
|
+
return [...prevSelectedItems, item];
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
const handleSelectAll = () => {
|
|
519
|
+
if (data && selectedItems.length === data.content.length) {
|
|
520
|
+
setSelectedItems([]);
|
|
521
|
+
} else if (data) {
|
|
522
|
+
setSelectedItems(data.content);
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
const isSelected = useCallback(
|
|
527
|
+
(item: T) => {
|
|
528
|
+
return selectedItems.some(
|
|
529
|
+
(selectedItem) =>
|
|
530
|
+
selectedItem[selectedItemKey as keyof T] ===
|
|
531
|
+
item[selectedItemKey as keyof T]
|
|
532
|
+
);
|
|
533
|
+
},
|
|
534
|
+
[selectedItems, selectedItemKey]
|
|
535
|
+
);
|
|
536
|
+
|
|
537
|
+
const nextPage = () => {
|
|
538
|
+
setCurrentPage((currentPage || 0) + 1);
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
const prevPage = () => {
|
|
542
|
+
setCurrentPage((currentPage || 0) - 1);
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
const handleSearchChanged = (
|
|
546
|
+
e: React.ChangeEvent<
|
|
547
|
+
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
|
|
548
|
+
>
|
|
549
|
+
) => {
|
|
550
|
+
setFulltextSearch(e.target?.value);
|
|
551
|
+
setCurrentPage(0);
|
|
552
|
+
};
|
|
553
|
+
// Pagination display logic
|
|
554
|
+
const paginationDisplay = `Strana ${(currentPage || 0) + 1} z ${data?.totalPages || 1}`;
|
|
555
|
+
|
|
556
|
+
const filterHandler = (
|
|
557
|
+
filterParam: keyof T,
|
|
558
|
+
value: string | string[],
|
|
559
|
+
filterParam2?: string,
|
|
560
|
+
clearFilterParam2?: boolean
|
|
561
|
+
) => {
|
|
562
|
+
setColumnFilters((prev) => {
|
|
563
|
+
const newFilters = { ...prev };
|
|
564
|
+
|
|
565
|
+
// Handle clearing both filters
|
|
566
|
+
if (
|
|
567
|
+
value === "" ||
|
|
568
|
+
value === "__clear__" ||
|
|
569
|
+
(Array.isArray(value) && value.length === 0)
|
|
570
|
+
) {
|
|
571
|
+
delete newFilters[String(filterParam)];
|
|
572
|
+
if (filterParam2) {
|
|
573
|
+
delete newFilters[filterParam2];
|
|
574
|
+
}
|
|
575
|
+
return newFilters;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// Handle filterParam2 logic
|
|
579
|
+
if (filterParam2) {
|
|
580
|
+
// Check if we should clear filterParam2
|
|
581
|
+
if (clearFilterParam2) {
|
|
582
|
+
newFilters[String(filterParam)] = value;
|
|
583
|
+
delete newFilters[filterParam2];
|
|
584
|
+
return newFilters;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Handle combined values with delimiter
|
|
588
|
+
if (typeof value === "string" && value.includes("-")) {
|
|
589
|
+
const parts = value.split("-");
|
|
590
|
+
if (parts.length === 2) {
|
|
591
|
+
newFilters[String(filterParam)] = parts[0];
|
|
592
|
+
newFilters[filterParam2] = parts[1];
|
|
593
|
+
return newFilters;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// Handle array values (multi-select) with subcategories
|
|
598
|
+
if (Array.isArray(value)) {
|
|
599
|
+
const subcategoryIds: string[] = [];
|
|
600
|
+
value.forEach((val: string) => {
|
|
601
|
+
if (val.includes("-")) {
|
|
602
|
+
const parts = val.split("-");
|
|
603
|
+
if (parts.length === 2) {
|
|
604
|
+
subcategoryIds.push(parts[1]);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
newFilters[String(filterParam)] =
|
|
610
|
+
value.length > 0 ? value : undefined;
|
|
611
|
+
if (subcategoryIds.length > 0) {
|
|
612
|
+
newFilters[filterParam2] = subcategoryIds;
|
|
613
|
+
} else {
|
|
614
|
+
delete newFilters[filterParam2];
|
|
615
|
+
}
|
|
616
|
+
return newFilters;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// Value without subcategory - clear filterParam2
|
|
620
|
+
newFilters[String(filterParam)] = value;
|
|
621
|
+
delete newFilters[filterParam2];
|
|
622
|
+
return newFilters;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Regular case without filterParam2
|
|
626
|
+
newFilters[String(filterParam)] = value;
|
|
627
|
+
return newFilters;
|
|
628
|
+
});
|
|
629
|
+
setCurrentPage(0);
|
|
630
|
+
};
|
|
631
|
+
const handleToggleShowColFilters = () => {
|
|
632
|
+
if (showColFilters && columnFilters !== undefined) {
|
|
633
|
+
setColumnFilters(columnFilters);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
setShowColFilters(!showColFilters);
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
// osetreni logiky pro useEffect. prvni nacteni filteru currentPage neresetuje
|
|
640
|
+
useEffect(() => {
|
|
641
|
+
if (!hasMounted) {
|
|
642
|
+
setHasMounted(true); // Ensures this block won't run again
|
|
643
|
+
} else {
|
|
644
|
+
setCurrentPage(0);
|
|
645
|
+
}
|
|
646
|
+
}, [filters]);
|
|
647
|
+
|
|
648
|
+
//store table settings in localstorage
|
|
649
|
+
useEffect(() => {
|
|
650
|
+
if (id && isLocalStorageLoaded) {
|
|
651
|
+
const storageKey = `datatable:${id}`;
|
|
652
|
+
|
|
653
|
+
const storageObject: DataTableStorageObject = localStorage.getItem(
|
|
654
|
+
storageKey
|
|
655
|
+
)
|
|
656
|
+
? (JSON.parse(
|
|
657
|
+
localStorage.getItem(storageKey)!
|
|
658
|
+
) as DataTableStorageObject)
|
|
659
|
+
: ({} as DataTableStorageObject);
|
|
660
|
+
|
|
661
|
+
storageObject.columnFilters = columnFilters || {};
|
|
662
|
+
// if (showColFilters !== undefined) {
|
|
663
|
+
// storageObject.showColFilters = showColFilters;
|
|
664
|
+
// }
|
|
665
|
+
storageObject.showColFilters = showColFilters || false;
|
|
666
|
+
storageObject.currentPage = currentPage || 0;
|
|
667
|
+
storageObject.sortConfig = sortConfig || null;
|
|
668
|
+
|
|
669
|
+
storageObject.itemsPerPage = itemsPerPageLocal || 10;
|
|
670
|
+
|
|
671
|
+
localStorage.setItem(storageKey, JSON.stringify(storageObject));
|
|
672
|
+
}
|
|
673
|
+
}, [
|
|
674
|
+
columnFilters,
|
|
675
|
+
showColFilters,
|
|
676
|
+
currentPage,
|
|
677
|
+
// id, // predbihalo se to a ukladaly se sortCOnfigy z predchozich tabulek
|
|
678
|
+
itemsPerPageLocal,
|
|
679
|
+
isLocalStorageLoaded,
|
|
680
|
+
sortConfig,
|
|
681
|
+
]);
|
|
682
|
+
|
|
683
|
+
const rerenderTable = () => {
|
|
684
|
+
setTableKey((previous) => previous + 1);
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
const exportToXLSX = useCallback(() => {
|
|
688
|
+
// load fresh complete data without pagination ,filters
|
|
689
|
+
setIsLoading(true);
|
|
690
|
+
|
|
691
|
+
//odebrani prazdny filteru a transformace multi-select hodnot
|
|
692
|
+
const filteredMergedFilters = Object.entries(mergedFilters || {}).reduce(
|
|
693
|
+
(acc: Record<string, any>, [key, value]) => {
|
|
694
|
+
// Skip null and empty string values
|
|
695
|
+
if (value === null || value === "") {
|
|
696
|
+
return acc;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// Handle multi-select values (arrays)
|
|
700
|
+
if (Array.isArray(value)) {
|
|
701
|
+
if (value.length > 0) {
|
|
702
|
+
acc[key] = value.join(",");
|
|
703
|
+
}
|
|
704
|
+
return acc;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Handle other values
|
|
708
|
+
acc[key] = value;
|
|
709
|
+
return acc;
|
|
710
|
+
},
|
|
711
|
+
{}
|
|
712
|
+
);
|
|
713
|
+
|
|
714
|
+
federationContext.apiClient
|
|
715
|
+
.get(url, {
|
|
716
|
+
params: {
|
|
717
|
+
...filteredMergedFilters,
|
|
718
|
+
pageSize: 1000000,
|
|
719
|
+
page: 0,
|
|
720
|
+
sortBy: sortConfig?.sortParam,
|
|
721
|
+
sortDirection: sortConfig?.direction,
|
|
722
|
+
},
|
|
723
|
+
})
|
|
724
|
+
.then((response) => {
|
|
725
|
+
setIsLoading(false);
|
|
726
|
+
const dataPageable: IPageable<T> = createDataPageable(
|
|
727
|
+
response,
|
|
728
|
+
1000000
|
|
729
|
+
);
|
|
730
|
+
|
|
731
|
+
const worksheet = XLSX.utils.json_to_sheet(
|
|
732
|
+
dataPageable.content.map((item: any) => {
|
|
733
|
+
const row = {};
|
|
734
|
+
columns.forEach((column) => {
|
|
735
|
+
let value;
|
|
736
|
+
if (column.renderXls) {
|
|
737
|
+
value = column.renderXls(item);
|
|
738
|
+
} else if (column.render) {
|
|
739
|
+
value = column.render(item)?.toString();
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// Handle number formatting
|
|
743
|
+
if (
|
|
744
|
+
column.renderXlsOptions?.type === "number" ||
|
|
745
|
+
typeof value === "number" ||
|
|
746
|
+
(typeof value === "string" && !isNaN(Number(value)))
|
|
747
|
+
) {
|
|
748
|
+
(row as any)[column.header] = Number(value);
|
|
749
|
+
} else {
|
|
750
|
+
(row as any)[column.header] = value?.toString();
|
|
751
|
+
}
|
|
752
|
+
});
|
|
753
|
+
return row;
|
|
754
|
+
})
|
|
755
|
+
);
|
|
756
|
+
|
|
757
|
+
// Apply number formatting to columns that contain numbers
|
|
758
|
+
const range = XLSX.utils.decode_range(worksheet["!ref"] || "A1");
|
|
759
|
+
for (let C = range.s.c; C <= range.e.c; ++C) {
|
|
760
|
+
const col = XLSX.utils.encode_col(C);
|
|
761
|
+
let hasNumbers = false;
|
|
762
|
+
|
|
763
|
+
// Check if column contains numbers
|
|
764
|
+
for (let R = range.s.r; R <= range.e.r; ++R) {
|
|
765
|
+
const cell = worksheet[col + (R + 1)];
|
|
766
|
+
if (cell && typeof cell.v === "number") {
|
|
767
|
+
hasNumbers = true;
|
|
768
|
+
break;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
// Apply number format if column contains numbers
|
|
772
|
+
if (hasNumbers) {
|
|
773
|
+
for (let R = range.s.r; R <= range.e.r; ++R) {
|
|
774
|
+
const cell = worksheet[col + (R + 1)];
|
|
775
|
+
if (cell && typeof cell.v === "number") {
|
|
776
|
+
// Get the column index by converting the column letter to number
|
|
777
|
+
const colIndex = XLSX.utils.decode_col(col);
|
|
778
|
+
// Find the corresponding column definition
|
|
779
|
+
const column = columns[colIndex];
|
|
780
|
+
// Apply the format if specified in renderXlsOptions
|
|
781
|
+
if (column?.renderXlsOptions?.format) {
|
|
782
|
+
cell.z = column.renderXlsOptions.format;
|
|
783
|
+
} else {
|
|
784
|
+
// Check if the number has decimal places
|
|
785
|
+
const hasDecimal = cell.v % 1 !== 0;
|
|
786
|
+
cell.z = hasDecimal ? "#,##0.##" : "#,##0"; // Use different formats based on whether decimals exist
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
const workbook = XLSX.utils.book_new();
|
|
794
|
+
XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
|
|
795
|
+
XLSX.writeFile(workbook, "export.xlsx");
|
|
796
|
+
})
|
|
797
|
+
.catch((error) => {
|
|
798
|
+
console.error("Error fetching data:", error);
|
|
799
|
+
handleErrors(error, federationContext.emitter);
|
|
800
|
+
setIsLoading(false);
|
|
801
|
+
});
|
|
802
|
+
}, [
|
|
803
|
+
setIsLoading,
|
|
804
|
+
federationContext.apiClient,
|
|
805
|
+
url,
|
|
806
|
+
mergedFilters,
|
|
807
|
+
showColFilters,
|
|
808
|
+
columnFilters,
|
|
809
|
+
sortConfig,
|
|
810
|
+
handleErrors,
|
|
811
|
+
columns,
|
|
812
|
+
]);
|
|
813
|
+
|
|
814
|
+
// Update sync width to match table content width
|
|
815
|
+
const updateSyncWidth = useCallback(() => {
|
|
816
|
+
if (tableRef.current && syncWidthRef.current && setMinWidth) {
|
|
817
|
+
syncWidthRef.current.style.width = tableRef.current.scrollWidth + "px";
|
|
818
|
+
}
|
|
819
|
+
}, [setMinWidth]);
|
|
820
|
+
|
|
821
|
+
// Set up scroll synchronization between top and bottom scrollbars
|
|
822
|
+
useEffect(() => {
|
|
823
|
+
if (!setMinWidth) return;
|
|
824
|
+
const topScrollbar = topScrollbarRef.current;
|
|
825
|
+
const bottomScrollbar = bottomScrollbarRef.current;
|
|
826
|
+
|
|
827
|
+
if (!topScrollbar || !bottomScrollbar) return;
|
|
828
|
+
|
|
829
|
+
const handleTopScroll = () => {
|
|
830
|
+
bottomScrollbar.scrollLeft = topScrollbar.scrollLeft;
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
const handleBottomScroll = () => {
|
|
834
|
+
topScrollbar.scrollLeft = bottomScrollbar.scrollLeft;
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
topScrollbar.addEventListener("scroll", handleTopScroll);
|
|
838
|
+
bottomScrollbar.addEventListener("scroll", handleBottomScroll);
|
|
839
|
+
|
|
840
|
+
return () => {
|
|
841
|
+
topScrollbar.removeEventListener("scroll", handleTopScroll);
|
|
842
|
+
bottomScrollbar.removeEventListener("scroll", handleBottomScroll);
|
|
843
|
+
};
|
|
844
|
+
}, [setMinWidth]);
|
|
845
|
+
|
|
846
|
+
// Set up ResizeObserver to update sync width when table content changes
|
|
847
|
+
useEffect(() => {
|
|
848
|
+
if (!tableRef.current) return;
|
|
849
|
+
|
|
850
|
+
const resizeObserver = new ResizeObserver(updateSyncWidth);
|
|
851
|
+
resizeObserver.observe(tableRef.current);
|
|
852
|
+
|
|
853
|
+
// Initial update
|
|
854
|
+
updateSyncWidth();
|
|
855
|
+
|
|
856
|
+
return () => {
|
|
857
|
+
resizeObserver.disconnect();
|
|
858
|
+
};
|
|
859
|
+
}, [updateSyncWidth, data, isLoading]);
|
|
860
|
+
|
|
861
|
+
const handleItemsPerPageChange = (value: string) => {
|
|
862
|
+
const selectedItemsPerPage = Number(value);
|
|
863
|
+
setItemsPerPageLocal(selectedItemsPerPage);
|
|
864
|
+
setCurrentPage(0); // Reset the current page to 0 when changing items per page
|
|
865
|
+
};
|
|
866
|
+
|
|
867
|
+
return (
|
|
868
|
+
<>
|
|
869
|
+
<div
|
|
870
|
+
className="shadow-lg border border-gray-200 rounded-xl"
|
|
871
|
+
style={{ overflowY: "visible" }}
|
|
872
|
+
data-cy={"datatable-container-" + id}
|
|
873
|
+
>
|
|
874
|
+
{showHeader && (
|
|
875
|
+
<div className="p-4 leading-9 flex ">
|
|
876
|
+
<div className="flex-grow content-center">
|
|
877
|
+
{title && (
|
|
878
|
+
<h1 className="font-semibold text-xl leading-[42px]">
|
|
879
|
+
{title}
|
|
880
|
+
</h1>
|
|
881
|
+
)}
|
|
882
|
+
{subtitle && (
|
|
883
|
+
<p className="font-normal text-gray-600">{subtitle}</p>
|
|
884
|
+
)}{" "}
|
|
885
|
+
{bulkAction && selectedItems.length > 0 && (
|
|
886
|
+
<div className="">{bulkAction(selectedItems)}</div>
|
|
887
|
+
)}
|
|
888
|
+
</div>
|
|
889
|
+
|
|
890
|
+
<DatatableSettings
|
|
891
|
+
tableId={id}
|
|
892
|
+
onSuccess={rerenderTable}
|
|
893
|
+
onExport={exportToXLSX}
|
|
894
|
+
></DatatableSettings>
|
|
895
|
+
{hasSomeColFilters && (
|
|
896
|
+
<div
|
|
897
|
+
className="flex items-center text-xl h-full p-3 cursor-pointer text-gray-500 hover:text-black"
|
|
898
|
+
title={
|
|
899
|
+
showColFilters
|
|
900
|
+
? "Zrušit filtr podle sloupců"
|
|
901
|
+
: "Filtrovat podle sloupců"
|
|
902
|
+
}
|
|
903
|
+
onClick={handleToggleShowColFilters}
|
|
904
|
+
data-cy="datatable-filter-toggle"
|
|
905
|
+
>
|
|
906
|
+
{!showColFilters && <MdOutlineFilterAlt />}
|
|
907
|
+
{showColFilters && (
|
|
908
|
+
<MdOutlineFilterAltOff className="text-danger" />
|
|
909
|
+
)}
|
|
910
|
+
</div>
|
|
911
|
+
)}
|
|
912
|
+
{allowSearch && (
|
|
913
|
+
<div className="ml-5">
|
|
914
|
+
<FormField
|
|
915
|
+
placeholder="Vyhledávání"
|
|
916
|
+
name="search"
|
|
917
|
+
onInputChange={handleSearchChanged}
|
|
918
|
+
type="text"
|
|
919
|
+
value={fulltextSearch}
|
|
920
|
+
>
|
|
921
|
+
<div className=" text-gray-500 leading-5 flex items-center h-full">
|
|
922
|
+
{!fulltextSearch && <MdSearch></MdSearch>}
|
|
923
|
+
{fulltextSearch && (
|
|
924
|
+
<MdClose onClick={() => setFulltextSearch("")} />
|
|
925
|
+
)}
|
|
926
|
+
</div>
|
|
927
|
+
</FormField>
|
|
928
|
+
</div>
|
|
929
|
+
)}
|
|
930
|
+
</div>
|
|
931
|
+
)}
|
|
932
|
+
{/* Top horizontal scrollbar */}
|
|
933
|
+
{setMinWidth && (
|
|
934
|
+
<div ref={topScrollbarRef} className="overflow-x-auto h-4 mb-1 mmmmm">
|
|
935
|
+
<div ref={syncWidthRef} className="h-full"></div>
|
|
936
|
+
</div>
|
|
937
|
+
)}
|
|
938
|
+
|
|
939
|
+
{/* Main scrollable content area */}
|
|
940
|
+
<div
|
|
941
|
+
ref={bottomScrollbarRef}
|
|
942
|
+
className="overflow-auto min-h-[500px] relative"
|
|
943
|
+
>
|
|
944
|
+
{isLoading && (
|
|
945
|
+
<div className="absolute inset-0 flex items-center justify-center h-[480px] py-2 z-10">
|
|
946
|
+
<Spinner />
|
|
947
|
+
</div>
|
|
948
|
+
)}
|
|
949
|
+
{!isLoading && (!data || data?.content?.length === 0) && (
|
|
950
|
+
<div className="absolute inset-0 flex items-center justify-center py-2 text-gray-600 font-medium text-xs top-[90px]">
|
|
951
|
+
Žádná data
|
|
952
|
+
</div>
|
|
953
|
+
)}
|
|
954
|
+
<table
|
|
955
|
+
ref={tableRef}
|
|
956
|
+
className="w-full leading-normal"
|
|
957
|
+
key={tableKey}
|
|
958
|
+
data-cy={"datatable-table-" + id}
|
|
959
|
+
>
|
|
960
|
+
<thead>
|
|
961
|
+
<tr>
|
|
962
|
+
{data && bulkAction && (
|
|
963
|
+
<th className="w-[20px] h-10 hover:bg-gray-200 bg-gray-50 font-medium text-xs text-center text-gray-600 cursor-pointer border-t border-b border-gray-200">
|
|
964
|
+
<label className="w-full h-full flex items-center justify-center cursor-pointer px-2">
|
|
965
|
+
<input
|
|
966
|
+
id="selectAll"
|
|
967
|
+
type="checkbox"
|
|
968
|
+
className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded !focus:ring-indigo-200 focus:ring-4"
|
|
969
|
+
onChange={handleSelectAll}
|
|
970
|
+
checked={
|
|
971
|
+
data &&
|
|
972
|
+
selectedItems.length === data.content.length &&
|
|
973
|
+
data.content.length > 0
|
|
974
|
+
}
|
|
975
|
+
/>
|
|
976
|
+
</label>
|
|
977
|
+
</th>
|
|
978
|
+
)}
|
|
979
|
+
{columns.map(
|
|
980
|
+
(
|
|
981
|
+
{
|
|
982
|
+
key,
|
|
983
|
+
header,
|
|
984
|
+
actions,
|
|
985
|
+
sortParam,
|
|
986
|
+
width,
|
|
987
|
+
filterType,
|
|
988
|
+
filterParam,
|
|
989
|
+
filterParam2,
|
|
990
|
+
},
|
|
991
|
+
index
|
|
992
|
+
) => (
|
|
993
|
+
<Resizable
|
|
994
|
+
// key={String(key) + currentPage}
|
|
995
|
+
key={String(key)}
|
|
996
|
+
tableId={id}
|
|
997
|
+
colKey={String(key)}
|
|
998
|
+
defaultWidth={width || "auto"}
|
|
999
|
+
setMinWidth={setMinWidth}
|
|
1000
|
+
>
|
|
1001
|
+
{({ ref }: { ref: any }) => {
|
|
1002
|
+
// Check if filter is active (non-empty)
|
|
1003
|
+
const hasActiveFilter = (() => {
|
|
1004
|
+
if (!filterParam) return false;
|
|
1005
|
+
|
|
1006
|
+
const filterValue = mergedFilters?.[String(filterParam)];
|
|
1007
|
+
const filterValue2 = filterParam2 ? mergedFilters?.[String(filterParam2)] : null;
|
|
1008
|
+
|
|
1009
|
+
if (filterType === "select") {
|
|
1010
|
+
return filterValue && filterValue !== "__clear__" && filterValue !== "";
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
if (filterType === "multi-select") {
|
|
1014
|
+
return Array.isArray(filterValue) && filterValue.length > 0;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
if (filterType === "dateRange") {
|
|
1018
|
+
return (filterValue && filterValue !== "") || (filterValue2 && filterValue2 !== "");
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
if (filterType === "date" || filterType === "text") {
|
|
1022
|
+
return filterValue && filterValue !== "";
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
return false;
|
|
1026
|
+
})();
|
|
1027
|
+
|
|
1028
|
+
return (
|
|
1029
|
+
<th
|
|
1030
|
+
className={`tableHeader relative font-medium text-xs !leading-9 text-left px-3 text-gray-600
|
|
1031
|
+
bg-gray-50 border-t border-b border-gray-200 content-start ${
|
|
1032
|
+
!title && !subtitle ? "border-t-0" : ""
|
|
1033
|
+
} ${sortParam ? " cursor-pointer " : ""} ${
|
|
1034
|
+
hasActiveFilter ? "!bg-[#f3f3f3] !shadow-[inset_0_2px_0_0_#525252] !text-black" : ""
|
|
1035
|
+
}`}
|
|
1036
|
+
onClick={() =>
|
|
1037
|
+
sortParam ? requestSort(sortParam) : undefined
|
|
1038
|
+
}
|
|
1039
|
+
data-cy={"datatable-header-" + id + "-" + String(key)}
|
|
1040
|
+
>
|
|
1041
|
+
<span className="inline-flex items-center gap-2 group select-none w-full">
|
|
1042
|
+
{header}{" "}
|
|
1043
|
+
{!actions && sortParam
|
|
1044
|
+
? getSortIcon(sortParam)
|
|
1045
|
+
: ""}
|
|
1046
|
+
</span>
|
|
1047
|
+
<div
|
|
1048
|
+
className={`resizer absolute top-0 right-0 h-full w-2 bg-transparent ${
|
|
1049
|
+
index < columns.length - 1
|
|
1050
|
+
? "cursor-col-resize hover:border-x border-gray-300 border-r w-1"
|
|
1051
|
+
: "w-0"
|
|
1052
|
+
}`}
|
|
1053
|
+
ref={ref}
|
|
1054
|
+
onClick={(e) => e.stopPropagation()}
|
|
1055
|
+
/>
|
|
1056
|
+
{showColFilters && (
|
|
1057
|
+
<div
|
|
1058
|
+
className="p-0 m-0 pb-2"
|
|
1059
|
+
onClick={(e) => e.stopPropagation()}
|
|
1060
|
+
data-cy={
|
|
1061
|
+
"datatable-filter-container-" +
|
|
1062
|
+
id +
|
|
1063
|
+
"-" +
|
|
1064
|
+
String(key)
|
|
1065
|
+
}
|
|
1066
|
+
>
|
|
1067
|
+
{filterType === "select" ? (
|
|
1068
|
+
<Select
|
|
1069
|
+
onValueChange={(value) => {
|
|
1070
|
+
if (value === "__clear__") {
|
|
1071
|
+
filterHandler(
|
|
1072
|
+
filterParam as keyof T,
|
|
1073
|
+
"",
|
|
1074
|
+
filterParam2
|
|
1075
|
+
);
|
|
1076
|
+
} else {
|
|
1077
|
+
// Check if value contains delimiter (has subcategory)
|
|
1078
|
+
if (value.includes("-") && filterParam2) {
|
|
1079
|
+
filterHandler(
|
|
1080
|
+
filterParam as keyof T,
|
|
1081
|
+
value,
|
|
1082
|
+
filterParam2
|
|
1083
|
+
);
|
|
1084
|
+
} else {
|
|
1085
|
+
// Value without subcategory - clear filterParam2 if it exists
|
|
1086
|
+
filterHandler(
|
|
1087
|
+
filterParam as keyof T,
|
|
1088
|
+
value,
|
|
1089
|
+
filterParam2,
|
|
1090
|
+
true
|
|
1091
|
+
);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
}}
|
|
1095
|
+
value={
|
|
1096
|
+
filterParam2 &&
|
|
1097
|
+
mergedFilters?.[String(filterParam)] &&
|
|
1098
|
+
mergedFilters?.[String(filterParam2)]
|
|
1099
|
+
? `${mergedFilters[String(filterParam)]}-${mergedFilters[String(filterParam2)]}`
|
|
1100
|
+
: mergedFilters?.[
|
|
1101
|
+
String(filterParam)
|
|
1102
|
+
]?.toString() || "__clear__"
|
|
1103
|
+
}
|
|
1104
|
+
disabled={Object.keys(
|
|
1105
|
+
(filters as object) || {}
|
|
1106
|
+
).includes(String(filterParam))}
|
|
1107
|
+
>
|
|
1108
|
+
<SelectTrigger className="flex-1 w-full px-2 font-normal placeholder-muted-foreground">
|
|
1109
|
+
<SelectValue placeholder="Zadejte filtr" />
|
|
1110
|
+
</SelectTrigger>
|
|
1111
|
+
<SelectContent>
|
|
1112
|
+
{filterOptions[String(filterParam)]
|
|
1113
|
+
?.filter(
|
|
1114
|
+
(option: IOptionItem) =>
|
|
1115
|
+
option.value !== null &&
|
|
1116
|
+
option.value !== undefined &&
|
|
1117
|
+
option.value !== ""
|
|
1118
|
+
)
|
|
1119
|
+
?.map((option: IOptionItem) => (
|
|
1120
|
+
<SelectItem
|
|
1121
|
+
key={option.value}
|
|
1122
|
+
value={
|
|
1123
|
+
option.value?.toString() ||
|
|
1124
|
+
"unknown"
|
|
1125
|
+
}
|
|
1126
|
+
>
|
|
1127
|
+
{option.label}
|
|
1128
|
+
</SelectItem>
|
|
1129
|
+
))}
|
|
1130
|
+
</SelectContent>
|
|
1131
|
+
</Select>
|
|
1132
|
+
) : filterType === "multi-select" ? (
|
|
1133
|
+
<MultiSelect
|
|
1134
|
+
// key={JSON.stringify(mergedFilters)}
|
|
1135
|
+
options={
|
|
1136
|
+
filterOptions[String(filterParam)] || []
|
|
1137
|
+
}
|
|
1138
|
+
onChange={(values) => {
|
|
1139
|
+
filterHandler(
|
|
1140
|
+
filterParam as keyof T,
|
|
1141
|
+
values,
|
|
1142
|
+
filterParam2
|
|
1143
|
+
);
|
|
1144
|
+
}}
|
|
1145
|
+
value={
|
|
1146
|
+
Array.isArray(
|
|
1147
|
+
mergedFilters?.[String(filterParam)]
|
|
1148
|
+
)
|
|
1149
|
+
? mergedFilters[String(filterParam)]
|
|
1150
|
+
: mergedFilters?.[String(filterParam)]
|
|
1151
|
+
? [mergedFilters[String(filterParam)]]
|
|
1152
|
+
: []
|
|
1153
|
+
}
|
|
1154
|
+
placeholder={"Zadejte filtr"}
|
|
1155
|
+
className="px-0"
|
|
1156
|
+
disabled={Object.keys(
|
|
1157
|
+
(filters as object) || {}
|
|
1158
|
+
).includes(String(filterParam))}
|
|
1159
|
+
variant="secondary"
|
|
1160
|
+
maxCount={0}
|
|
1161
|
+
/>
|
|
1162
|
+
) : filterType === "dateRange" ? (
|
|
1163
|
+
<DateRangeField
|
|
1164
|
+
// key={JSON.stringify(mergedFilters)}
|
|
1165
|
+
name={String(filterParam)}
|
|
1166
|
+
nameEnd={String(filterParam2)}
|
|
1167
|
+
onInputChange={(e) =>
|
|
1168
|
+
filterHandler(
|
|
1169
|
+
e.target.name as keyof T,
|
|
1170
|
+
e.target.value
|
|
1171
|
+
)
|
|
1172
|
+
}
|
|
1173
|
+
type={filterType}
|
|
1174
|
+
value={{
|
|
1175
|
+
startDate:
|
|
1176
|
+
mergedFilters?.[String(filterParam)] ||
|
|
1177
|
+
"",
|
|
1178
|
+
endDate:
|
|
1179
|
+
mergedFilters?.[String(filterParam2)] ||
|
|
1180
|
+
"",
|
|
1181
|
+
}}
|
|
1182
|
+
clearable
|
|
1183
|
+
className=" px-0 py-0 "
|
|
1184
|
+
placeholder={"Zadejte filtr"}
|
|
1185
|
+
rounded={true}
|
|
1186
|
+
disabled={Object.keys(
|
|
1187
|
+
(filters as object) || {}
|
|
1188
|
+
).includes(String(filterParam))}
|
|
1189
|
+
/>
|
|
1190
|
+
) : filterType === "date" ? (
|
|
1191
|
+
<DateField
|
|
1192
|
+
// key={JSON.stringify(mergedFilters)}
|
|
1193
|
+
name={String(filterParam)}
|
|
1194
|
+
onInputChange={(e) =>
|
|
1195
|
+
filterHandler(
|
|
1196
|
+
e.target.name as keyof T,
|
|
1197
|
+
e.target.value
|
|
1198
|
+
)
|
|
1199
|
+
}
|
|
1200
|
+
type={filterType}
|
|
1201
|
+
value={
|
|
1202
|
+
mergedFilters?.[String(filterParam)] || ""
|
|
1203
|
+
}
|
|
1204
|
+
clearable
|
|
1205
|
+
className=" px-0 py-0 "
|
|
1206
|
+
placeholder={"Zadejte filtr"}
|
|
1207
|
+
rounded={true}
|
|
1208
|
+
disabled={Object.keys(
|
|
1209
|
+
(filters as object) || {}
|
|
1210
|
+
).includes(String(filterParam))}
|
|
1211
|
+
/>
|
|
1212
|
+
) : filterType === "text" ? (
|
|
1213
|
+
<Input
|
|
1214
|
+
onChange={(e) =>
|
|
1215
|
+
filterHandler(
|
|
1216
|
+
filterParam as keyof T,
|
|
1217
|
+
e.target.value
|
|
1218
|
+
)
|
|
1219
|
+
}
|
|
1220
|
+
value={
|
|
1221
|
+
mergedFilters?.[String(filterParam)] || ""
|
|
1222
|
+
}
|
|
1223
|
+
disabled={Object.keys(
|
|
1224
|
+
(filters as object) || {}
|
|
1225
|
+
).includes(String(filterParam))}
|
|
1226
|
+
clearable
|
|
1227
|
+
className="min-w-[100px] px-2 font-normal placeholder-muted-foreground
|
|
1228
|
+
"
|
|
1229
|
+
placeholder={"Zadejte filtr"}
|
|
1230
|
+
debounceTimeout={1000}
|
|
1231
|
+
/>
|
|
1232
|
+
) : null}
|
|
1233
|
+
</div>
|
|
1234
|
+
)}
|
|
1235
|
+
</th>
|
|
1236
|
+
);
|
|
1237
|
+
}}
|
|
1238
|
+
</Resizable>
|
|
1239
|
+
)
|
|
1240
|
+
)}
|
|
1241
|
+
</tr>
|
|
1242
|
+
</thead>
|
|
1243
|
+
{!isLoading &&
|
|
1244
|
+
data &&
|
|
1245
|
+
data?.content &&
|
|
1246
|
+
data?.content.length > 0 && (
|
|
1247
|
+
<tbody className="relative">
|
|
1248
|
+
{data.content.map((item, rowIndex) => (
|
|
1249
|
+
<tr
|
|
1250
|
+
key={rowIndex}
|
|
1251
|
+
className={`${
|
|
1252
|
+
item._isHighlighted || isSelected(item)
|
|
1253
|
+
? "bg-gray-50"
|
|
1254
|
+
: ""
|
|
1255
|
+
} hover:bg-gray-100 border-gray-200 border-b text-sm`}
|
|
1256
|
+
>
|
|
1257
|
+
{bulkAction && (
|
|
1258
|
+
<td className="w-[20px] h-[52px] hover:bg-gray-200 font-medium text-xs text-center text-gray-600 cursor-pointer">
|
|
1259
|
+
<label className="w-full h-full flex items-center justify-center cursor-pointer px-2">
|
|
1260
|
+
<input
|
|
1261
|
+
type="checkbox"
|
|
1262
|
+
className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded !focus:ring-indigo-200 focus:ring-4"
|
|
1263
|
+
checked={isSelected(item) || false}
|
|
1264
|
+
onChange={() => handleSelectItem(item)}
|
|
1265
|
+
/>
|
|
1266
|
+
</label>
|
|
1267
|
+
</td>
|
|
1268
|
+
)}
|
|
1269
|
+
{columns.map(({ render, actions, classes }, colIndex) => (
|
|
1270
|
+
<td
|
|
1271
|
+
key={`${rowIndex}-${colIndex}`}
|
|
1272
|
+
onClick={
|
|
1273
|
+
rowAction ? () => rowAction(item) : undefined
|
|
1274
|
+
}
|
|
1275
|
+
className={`px-3 py-2 text-gray-800 ${rowAction ? "cursor-pointer" : ""} ${
|
|
1276
|
+
colIndex === 0 ? "font-bold " : ""
|
|
1277
|
+
} ${classes || ""}`}
|
|
1278
|
+
>
|
|
1279
|
+
{render ? render(item) : ""}
|
|
1280
|
+
{actions &&
|
|
1281
|
+
actions
|
|
1282
|
+
.filter((it) => {
|
|
1283
|
+
if (it.rowAction) return false;
|
|
1284
|
+
if (it.visible) {
|
|
1285
|
+
return it.visible(item);
|
|
1286
|
+
} else return true;
|
|
1287
|
+
})
|
|
1288
|
+
.map((action, actionIndex) => (
|
|
1289
|
+
<div
|
|
1290
|
+
key={`${rowIndex}-${colIndex}-${actionIndex}`}
|
|
1291
|
+
className="inline-flex align-middle"
|
|
1292
|
+
>
|
|
1293
|
+
{action.icon && (
|
|
1294
|
+
<Button
|
|
1295
|
+
variant="icon"
|
|
1296
|
+
onClick={() => action.onClick(item)}
|
|
1297
|
+
>
|
|
1298
|
+
{action.icon}
|
|
1299
|
+
</Button>
|
|
1300
|
+
)}
|
|
1301
|
+
{!action.icon && (
|
|
1302
|
+
<Button
|
|
1303
|
+
variant="primary"
|
|
1304
|
+
onClick={(e) => {
|
|
1305
|
+
e.stopPropagation();
|
|
1306
|
+
action.onClick(item);
|
|
1307
|
+
}}
|
|
1308
|
+
>
|
|
1309
|
+
{action.label}
|
|
1310
|
+
</Button>
|
|
1311
|
+
)}
|
|
1312
|
+
</div>
|
|
1313
|
+
))}
|
|
1314
|
+
</td>
|
|
1315
|
+
))}
|
|
1316
|
+
</tr>
|
|
1317
|
+
))}
|
|
1318
|
+
{data?.content?.length === 0 && (
|
|
1319
|
+
<tr key="tr-nodata">
|
|
1320
|
+
<td
|
|
1321
|
+
key="td-nodata"
|
|
1322
|
+
className="px-5 py-3 border-b border-gray-200 bg-white text-sm items-center justify-center align-middle"
|
|
1323
|
+
colSpan={columns.length}
|
|
1324
|
+
>
|
|
1325
|
+
No data
|
|
1326
|
+
</td>
|
|
1327
|
+
</tr>
|
|
1328
|
+
)}
|
|
1329
|
+
</tbody>
|
|
1330
|
+
)}
|
|
1331
|
+
</table>
|
|
1332
|
+
</div>
|
|
1333
|
+
|
|
1334
|
+
{data?.isPageable && (
|
|
1335
|
+
<div
|
|
1336
|
+
data-cy="pagination"
|
|
1337
|
+
className="w-full p-5 flex gap-5 justify-between md:flex-row flex-col"
|
|
1338
|
+
>
|
|
1339
|
+
<div className="flex gap-5 text-sm ">
|
|
1340
|
+
{data && (
|
|
1341
|
+
<Button
|
|
1342
|
+
variant="secondary"
|
|
1343
|
+
onClick={prevPage}
|
|
1344
|
+
className="flex items-center"
|
|
1345
|
+
disabled={data.first || isLoading}
|
|
1346
|
+
data-cy="prev-page"
|
|
1347
|
+
>
|
|
1348
|
+
<MdArrowBack className="mr-1.5" /> Předchozí
|
|
1349
|
+
</Button>
|
|
1350
|
+
)}
|
|
1351
|
+
{data && (
|
|
1352
|
+
<Button
|
|
1353
|
+
variant="secondary"
|
|
1354
|
+
onClick={nextPage}
|
|
1355
|
+
className="flex items-center"
|
|
1356
|
+
disabled={data.last || isLoading}
|
|
1357
|
+
data-cy="next-page"
|
|
1358
|
+
>
|
|
1359
|
+
Následující <MdArrowForward className="ml-2" size={20} />
|
|
1360
|
+
</Button>
|
|
1361
|
+
)}
|
|
1362
|
+
</div>
|
|
1363
|
+
<div className="flex items-center justify-center text-gray-800">
|
|
1364
|
+
{paginationDisplay}
|
|
1365
|
+
</div>
|
|
1366
|
+
<div
|
|
1367
|
+
className="content-center w-auto items-center justify-end flex-row gap-5 flex md:mt-0 mt-5"
|
|
1368
|
+
data-cy="items-per-page"
|
|
1369
|
+
>
|
|
1370
|
+
<span className=" whitespace-nowrap flex-grow">
|
|
1371
|
+
Počet řádků na stránku:
|
|
1372
|
+
</span>
|
|
1373
|
+
<Select
|
|
1374
|
+
onValueChange={handleItemsPerPageChange}
|
|
1375
|
+
value={itemsPerPageLocal?.toString()}
|
|
1376
|
+
>
|
|
1377
|
+
<SelectTrigger className="w-[100px]">
|
|
1378
|
+
<SelectValue placeholder="Vyberte počet" />
|
|
1379
|
+
</SelectTrigger>
|
|
1380
|
+
<SelectContent>
|
|
1381
|
+
{itemsPerPageOptions?.map((option) => (
|
|
1382
|
+
<SelectItem
|
|
1383
|
+
key={option.value}
|
|
1384
|
+
value={option.value?.toString() || ""}
|
|
1385
|
+
>
|
|
1386
|
+
{option.label}
|
|
1387
|
+
</SelectItem>
|
|
1388
|
+
))}
|
|
1389
|
+
</SelectContent>
|
|
1390
|
+
</Select>
|
|
1391
|
+
</div>
|
|
1392
|
+
</div>
|
|
1393
|
+
)}
|
|
1394
|
+
</div>
|
|
1395
|
+
</>
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
export default DataTableServer;
|