@cdc/dashboard 4.25.3 → 4.25.5-1
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/Dynamic_Data.md +79 -0
- package/Override_Data.md +39 -0
- package/dist/cdcdashboard.js +67657 -70123
- package/examples/legend-issue-data.json +1874 -0
- package/examples/legend-issue.json +749 -0
- package/examples/map.json +628 -0
- package/index.html +1 -26
- package/package.json +10 -15
- package/src/CdcDashboardComponent.tsx +32 -5
- package/src/_stories/Dashboard.stories.tsx +2 -0
- package/src/_stories/_mock/api-filter-map.json +42 -1
- package/src/components/CollapsibleVisualizationRow.tsx +2 -2
- package/src/components/DashboardFilters/DashboardFilters.tsx +1 -1
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/APIModal.tsx +129 -0
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +680 -652
- package/src/components/DataDesignerModal.tsx +33 -14
- package/src/components/MultiConfigTabs/multiconfigtabs.styles.css +3 -0
- package/src/components/Row.tsx +2 -1
- package/src/components/VisualizationRow.tsx +1 -1
- package/src/helpers/reloadURLHelpers.ts +10 -2
- package/src/helpers/shouldLoadAllFilters.ts +30 -30
- package/src/index.tsx +2 -1
- package/src/scss/main.scss +0 -5
- package/src/store/dashboard.actions.ts +2 -0
- package/src/store/dashboard.reducer.ts +15 -0
- package/src/types/DataSet.ts +1 -0
- package/src/types/SharedFilter.ts +2 -0
- package/LICENSE +0 -201
- package/examples/private/DEV-10120.json +0 -1294
- package/examples/private/DEV-10527.json +0 -845
- package/examples/private/DEV-10586.json +0 -54319
- package/examples/private/DEV-10856.json +0 -54319
- package/examples/private/DEV-9199.json +0 -606
- package/examples/private/DEV-9644.json +0 -20092
- package/examples/private/DEV-9684.json +0 -2135
- package/examples/private/DEV-9932.json +0 -95
- package/examples/private/DEV-9989.json +0 -229
- package/examples/private/art-dashboard.json +0 -18174
- package/examples/private/art-scratch.json +0 -2406
- package/examples/private/bird-flu-2.json +0 -440
- package/examples/private/bird-flu.json +0 -413
- package/examples/private/dashboard-config-ehdi.json +0 -29915
- package/examples/private/dashboard-map-filter.json +0 -815
- package/examples/private/dashboard-margins.js +0 -15
- package/examples/private/dataset.json +0 -1452
- package/examples/private/dev-10856-2.json +0 -1348
- package/examples/private/ehdi-data.json +0 -29502
- package/examples/private/exposure-source-h5-data.csv +0 -26
- package/examples/private/fatal-data.csv +0 -3159
- package/examples/private/feelings.json +0 -1
- package/examples/private/gaza-issue.json +0 -1214
- package/examples/private/markup.json +0 -115
- package/examples/private/nhis.json +0 -1792
- package/examples/private/workforce.json +0 -2041
|
@@ -1,652 +1,680 @@
|
|
|
1
|
-
import _ from 'lodash'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import
|
|
19
|
-
import {
|
|
20
|
-
import
|
|
21
|
-
import {
|
|
22
|
-
import
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
updateFilterProp('
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
<
|
|
315
|
-
{
|
|
316
|
-
</
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
</
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
<
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
</
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
<Tooltip.
|
|
444
|
-
<
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
label:
|
|
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
|
-
<span>
|
|
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
|
-
|
|
1
|
+
import _ from 'lodash'
|
|
2
|
+
import { getVizRowColumnLocator } from '../../../../helpers/getVizRowColumnLocator'
|
|
3
|
+
import { Select, TextField } from '@cdc/core/components/EditorPanel/Inputs'
|
|
4
|
+
import DataTransform from '@cdc/core/helpers/DataTransform'
|
|
5
|
+
import { useEffect, useMemo, useState } from 'react'
|
|
6
|
+
import { SharedFilter } from '../../../../types/SharedFilter'
|
|
7
|
+
|
|
8
|
+
import fetchRemoteData from '@cdc/core/helpers/fetchRemoteData'
|
|
9
|
+
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
10
|
+
import Icon from '@cdc/core/components/ui/Icon'
|
|
11
|
+
import MultiSelect from '@cdc/core/components/MultiSelect'
|
|
12
|
+
import Loading from '@cdc/core/components/Loading'
|
|
13
|
+
import { DashboardConfig } from '../../../../types/DashboardConfig'
|
|
14
|
+
import { Visualization } from '@cdc/core/types/Visualization'
|
|
15
|
+
import { hasDashboardApplyBehavior } from '../../../../helpers/hasDashboardApplyBehavior'
|
|
16
|
+
import APIModal from './APIModal'
|
|
17
|
+
import NestedDropDownDashboard from './NestedDropDownDashboard'
|
|
18
|
+
import { FILTER_STYLE } from '../../../../types/FilterStyles'
|
|
19
|
+
import { filterOrderOptions } from '@cdc/core/helpers/filterOrderOptions'
|
|
20
|
+
import FilterOrder from '@cdc/core/components/EditorPanel/VizFilterEditor/components/FilterOrder'
|
|
21
|
+
import { useGlobalContext } from '@cdc/core/components/GlobalContext'
|
|
22
|
+
import Modal from '@cdc/core/components/ui/Modal'
|
|
23
|
+
|
|
24
|
+
type FilterEditorProps = {
|
|
25
|
+
config: DashboardConfig
|
|
26
|
+
filter: SharedFilter
|
|
27
|
+
filterIndex: number
|
|
28
|
+
updateFilterProp: (name: keyof SharedFilter, value: any) => void
|
|
29
|
+
toggleNestedQueryParameters: (checked: boolean) => void
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const FilterEditor: React.FC<FilterEditorProps> = ({
|
|
33
|
+
filter,
|
|
34
|
+
filterIndex,
|
|
35
|
+
config,
|
|
36
|
+
updateFilterProp,
|
|
37
|
+
toggleNestedQueryParameters
|
|
38
|
+
}) => {
|
|
39
|
+
const [columns, setColumns] = useState<string[]>([])
|
|
40
|
+
const [dataFiltersLoading, setDataFiltersLoading] = useState(false)
|
|
41
|
+
|
|
42
|
+
const transform = new DataTransform()
|
|
43
|
+
const filterStyles = Object.values(FILTER_STYLE)
|
|
44
|
+
|
|
45
|
+
const parentFilters: string[] = (config.dashboard.sharedFilters || [])
|
|
46
|
+
.filter(({ key, type }) => key !== filter.key && type !== 'datafilter')
|
|
47
|
+
.map(({ key }) => key)
|
|
48
|
+
|
|
49
|
+
const vizRowColumnLocator = getVizRowColumnLocator(config.rows)
|
|
50
|
+
|
|
51
|
+
const getVizTitle = (viz, vizKey) => {
|
|
52
|
+
let vizName = viz.general?.title || viz.title || vizKey
|
|
53
|
+
if (viz.visualizationType === 'markup-include') {
|
|
54
|
+
vizName = viz.contentEditor.title || vizKey
|
|
55
|
+
}
|
|
56
|
+
return vizName
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const [usedByNameLookup, usedByOptions] = useMemo(() => {
|
|
60
|
+
const nameLookup = {}
|
|
61
|
+
const vizOptions = Object.keys(config.visualizations).filter(vizKey => {
|
|
62
|
+
const vizLookup = vizRowColumnLocator[vizKey]
|
|
63
|
+
if (!vizLookup) return false
|
|
64
|
+
const viz = config.visualizations[vizKey] as Visualization
|
|
65
|
+
if (viz.type === 'dashboardFilters') return false
|
|
66
|
+
const vizName = getVizTitle(viz, vizKey)
|
|
67
|
+
|
|
68
|
+
nameLookup[vizKey] = vizName
|
|
69
|
+
const usesSharedFilter = viz.usesSharedFilter
|
|
70
|
+
const rowIndex = vizLookup.row
|
|
71
|
+
const dataConfiguredOnRow = config.rows[rowIndex].dataKey
|
|
72
|
+
return filter.setBy !== vizKey && !usesSharedFilter && !dataConfiguredOnRow
|
|
73
|
+
})
|
|
74
|
+
const rowOptions: number[] = []
|
|
75
|
+
|
|
76
|
+
config.rows.forEach((row, rowIndex) => {
|
|
77
|
+
if (!!row.dataKey) {
|
|
78
|
+
nameLookup[rowIndex] = `Row ${rowIndex + 1}`
|
|
79
|
+
rowOptions.push(rowIndex)
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const rowsNotSelected = rowOptions.filter(row => !filter.usedBy || filter.usedBy.indexOf(row.toString()) === -1)
|
|
84
|
+
return [nameLookup, [...vizOptions, ...rowsNotSelected]]
|
|
85
|
+
}, [config.visualizations, filter.usedBy, filter.setBy, vizRowColumnLocator])
|
|
86
|
+
|
|
87
|
+
const useParameters = useMemo(() => {
|
|
88
|
+
if (filter.subGrouping) return !!(filter.setByQueryParameter && filter.subGrouping?.setByQueryParameter)
|
|
89
|
+
return !!filter.setByQueryParameter
|
|
90
|
+
}, [config, filterIndex])
|
|
91
|
+
|
|
92
|
+
const loadColumnData = async () => {
|
|
93
|
+
// column data only needed for data filters
|
|
94
|
+
if (!config.dashboard.sharedFilters.some(f => f.type === 'datafilter')) return
|
|
95
|
+
const columns = {}
|
|
96
|
+
const dataKeys = Object.keys(config.datasets)
|
|
97
|
+
for (let i = 0; i < dataKeys.length; i++) {
|
|
98
|
+
const dataKey = dataKeys[i]
|
|
99
|
+
let _dataSet = config.datasets[dataKey]
|
|
100
|
+
if (!_dataSet.data && _dataSet.dataUrl) {
|
|
101
|
+
setDataFiltersLoading(true)
|
|
102
|
+
let data = await fetchRemoteData(_dataSet.dataUrl)
|
|
103
|
+
if (_dataSet.dataDescription) {
|
|
104
|
+
try {
|
|
105
|
+
data = transform.autoStandardize(data)
|
|
106
|
+
data = transform.developerStandardize(data, _dataSet.dataDescription)
|
|
107
|
+
} catch (e) {
|
|
108
|
+
console.error(e)
|
|
109
|
+
//Data not able to be standardized, leave as is
|
|
110
|
+
} finally {
|
|
111
|
+
_dataSet.data = data
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (_dataSet.data) {
|
|
117
|
+
_dataSet.data.forEach(row => {
|
|
118
|
+
Object.keys(row).forEach(columnName => {
|
|
119
|
+
columns[columnName] = true
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
setDataFiltersLoading(false)
|
|
125
|
+
setColumns(Object.keys(columns))
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
loadColumnData()
|
|
130
|
+
}, [config.datasets, config.dashboard.sharedFilters])
|
|
131
|
+
|
|
132
|
+
const updateAPIFilter = (apiEndpoint, valueSelector, textSelector, subgroupValueSelector, subgroupTextSelector) => {
|
|
133
|
+
const newAPIFilter = !isNestedDropdown
|
|
134
|
+
? {
|
|
135
|
+
apiEndpoint,
|
|
136
|
+
valueSelector,
|
|
137
|
+
textSelector
|
|
138
|
+
}
|
|
139
|
+
: {
|
|
140
|
+
apiEndpoint,
|
|
141
|
+
valueSelector,
|
|
142
|
+
textSelector,
|
|
143
|
+
subgroupValueSelector,
|
|
144
|
+
subgroupTextSelector
|
|
145
|
+
}
|
|
146
|
+
updateFilterProp('apiFilter', newAPIFilter)
|
|
147
|
+
overlay.actions.toggleOverlay(false)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const updateLabel = (value: string) => {
|
|
151
|
+
const duplicateLabels = config.dashboard.sharedFilters.filter(
|
|
152
|
+
(filter, i) => filter.key === value && filterIndex !== i
|
|
153
|
+
)
|
|
154
|
+
// If there are duplicate labels, append the number of duplicates to the label similar functionality to duplicate file names
|
|
155
|
+
updateFilterProp('key', duplicateLabels.length ? value + ` (${duplicateLabels.length})` : value)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const isNestedDropdown = filter.filterStyle === FILTER_STYLE.nestedDropdown
|
|
159
|
+
|
|
160
|
+
const { overlay } = useGlobalContext()
|
|
161
|
+
|
|
162
|
+
const handleEditAPIValues = (filter, isNestedDropdown, updateAPIFilter) => {
|
|
163
|
+
{
|
|
164
|
+
overlay.actions.openOverlay(
|
|
165
|
+
<Modal>
|
|
166
|
+
<Modal.Content>
|
|
167
|
+
<APIModal filter={filter} isNestedDropdown={isNestedDropdown} updateAPIFilter={updateAPIFilter} />
|
|
168
|
+
</Modal.Content>
|
|
169
|
+
</Modal>
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const selectFilterType = (type: string) => {
|
|
175
|
+
updateFilterProp('type', type)
|
|
176
|
+
if (type === 'datafilter') {
|
|
177
|
+
loadColumnData()
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
<>
|
|
183
|
+
{dataFiltersLoading && <Loading />}
|
|
184
|
+
<label>
|
|
185
|
+
<span className='edit-label column-heading'>Filter Type: </span>
|
|
186
|
+
<select
|
|
187
|
+
defaultValue={filter.type || ''}
|
|
188
|
+
onChange={e => selectFilterType(e.target.value)}
|
|
189
|
+
disabled={!!filter.type}
|
|
190
|
+
>
|
|
191
|
+
<option value=''>- Select Option -</option>
|
|
192
|
+
<option value='urlfilter'>URL</option>
|
|
193
|
+
<option value='datafilter'>Data</option>
|
|
194
|
+
</select>
|
|
195
|
+
</label>
|
|
196
|
+
{filter.type !== undefined && (
|
|
197
|
+
<>
|
|
198
|
+
<label>
|
|
199
|
+
<span className='edit-label column-heading'>Filter Style: </span>
|
|
200
|
+
<select
|
|
201
|
+
value={filter.filterStyle || FILTER_STYLE.dropdown}
|
|
202
|
+
onChange={e => updateFilterProp('filterStyle', e.target.value)}
|
|
203
|
+
>
|
|
204
|
+
{filterStyles.map(dataKey => (
|
|
205
|
+
<option value={dataKey} key={`filter-style-select-item-${dataKey}`}>
|
|
206
|
+
{dataKey}
|
|
207
|
+
</option>
|
|
208
|
+
))}
|
|
209
|
+
</select>
|
|
210
|
+
</label>
|
|
211
|
+
{filter.filterStyle === FILTER_STYLE.dropdown && (
|
|
212
|
+
<label>
|
|
213
|
+
<span className='me-1'>Show Dropdown</span>
|
|
214
|
+
<input
|
|
215
|
+
type='checkbox'
|
|
216
|
+
checked={filter.showDropdown}
|
|
217
|
+
onChange={e => {
|
|
218
|
+
updateFilterProp('showDropdown', !filter.showDropdown)
|
|
219
|
+
}}
|
|
220
|
+
/>
|
|
221
|
+
</label>
|
|
222
|
+
)}
|
|
223
|
+
|
|
224
|
+
<TextField
|
|
225
|
+
label='Label'
|
|
226
|
+
value={filter.key}
|
|
227
|
+
updateField={(_section, _subSection, _key, value) => {
|
|
228
|
+
updateLabel(value)
|
|
229
|
+
}}
|
|
230
|
+
/>
|
|
231
|
+
{filter.filterStyle === FILTER_STYLE.multiSelect && (
|
|
232
|
+
<TextField
|
|
233
|
+
label='Select Limit'
|
|
234
|
+
value={filter.selectLimit}
|
|
235
|
+
updateField={(_section, _subSection, _field, value) => updateFilterProp('selectLimit', value)}
|
|
236
|
+
type='number'
|
|
237
|
+
tooltip={
|
|
238
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
239
|
+
<Tooltip.Target>
|
|
240
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
241
|
+
</Tooltip.Target>
|
|
242
|
+
<Tooltip.Content>
|
|
243
|
+
<p>The maximum number of items that can be selected.</p>
|
|
244
|
+
</Tooltip.Content>
|
|
245
|
+
</Tooltip>
|
|
246
|
+
}
|
|
247
|
+
/>
|
|
248
|
+
)}
|
|
249
|
+
|
|
250
|
+
{filter.type === 'urlfilter' && (
|
|
251
|
+
<>
|
|
252
|
+
{!hasDashboardApplyBehavior(config.visualizations) && (
|
|
253
|
+
<>
|
|
254
|
+
<label>
|
|
255
|
+
<span className='edit-label column-heading'>URL to Filter: </span>
|
|
256
|
+
<select
|
|
257
|
+
defaultValue={filter.datasetKey || ''}
|
|
258
|
+
onChange={e => updateFilterProp('datasetKey', e.target.value)}
|
|
259
|
+
>
|
|
260
|
+
<option value=''>- Select Option -</option>
|
|
261
|
+
{Object.keys(config.datasets).map(datasetKey => {
|
|
262
|
+
if (config.datasets[datasetKey].dataUrl) {
|
|
263
|
+
return (
|
|
264
|
+
<option key={datasetKey} value={datasetKey}>
|
|
265
|
+
{config.datasets[datasetKey].dataUrl}
|
|
266
|
+
</option>
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
return null
|
|
270
|
+
})}
|
|
271
|
+
</select>
|
|
272
|
+
</label>
|
|
273
|
+
|
|
274
|
+
<label>
|
|
275
|
+
<span className='edit-label column-heading'>Filter By: </span>
|
|
276
|
+
<select
|
|
277
|
+
defaultValue={filter.filterBy || ''}
|
|
278
|
+
onChange={e => updateFilterProp('filterBy', e.target.value)}
|
|
279
|
+
>
|
|
280
|
+
<option value=''>- Select Option -</option>
|
|
281
|
+
<option key={'query-string'} value={'Query String'}>
|
|
282
|
+
Query String
|
|
283
|
+
</option>
|
|
284
|
+
<option key={'file-name'} value={'File Name'}>
|
|
285
|
+
File Name
|
|
286
|
+
</option>
|
|
287
|
+
</select>
|
|
288
|
+
</label>
|
|
289
|
+
{filter.filterBy === 'File Name' && (
|
|
290
|
+
<>
|
|
291
|
+
<TextField
|
|
292
|
+
label='File Name: '
|
|
293
|
+
value={filter.fileName || ''}
|
|
294
|
+
updateField={(_section, _subSection, _key, value) => updateFilterProp('fileName', value)}
|
|
295
|
+
tooltip={
|
|
296
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
297
|
+
<Tooltip.Target>
|
|
298
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
299
|
+
</Tooltip.Target>
|
|
300
|
+
<Tooltip.Content>
|
|
301
|
+
<p>{`Add \${query}\ to replace the filename with the active dropdown value.`}</p>
|
|
302
|
+
</Tooltip.Content>
|
|
303
|
+
</Tooltip>
|
|
304
|
+
}
|
|
305
|
+
/>
|
|
306
|
+
|
|
307
|
+
<label>
|
|
308
|
+
<span className='edit-label column-heading'>
|
|
309
|
+
White Space Replacments
|
|
310
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
311
|
+
<Tooltip.Target>
|
|
312
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
313
|
+
</Tooltip.Target>
|
|
314
|
+
<Tooltip.Content>
|
|
315
|
+
<p>{`Set how whitespace characters will be handled in the file request`}</p>
|
|
316
|
+
</Tooltip.Content>
|
|
317
|
+
</Tooltip>
|
|
318
|
+
</span>
|
|
319
|
+
<select
|
|
320
|
+
defaultValue={filter.whitespaceReplacement || 'Keep Spaces'}
|
|
321
|
+
onChange={e => updateFilterProp('whitespaceReplacement', e.target.value)}
|
|
322
|
+
>
|
|
323
|
+
<option key={'remove-spaces'} value={'Remove Spaces'}>
|
|
324
|
+
Remove Spaces
|
|
325
|
+
</option>
|
|
326
|
+
<option key={'replace-with-underscore'} value={'Replace With Underscore'}>
|
|
327
|
+
Replace With Underscore
|
|
328
|
+
</option>
|
|
329
|
+
<option key={'keep-spaces'} value={'Keep Spaces'}>
|
|
330
|
+
Keep Spaces
|
|
331
|
+
</option>
|
|
332
|
+
</select>
|
|
333
|
+
</label>
|
|
334
|
+
</>
|
|
335
|
+
)}
|
|
336
|
+
</>
|
|
337
|
+
)}
|
|
338
|
+
{filter.filterBy === 'Query String' && (
|
|
339
|
+
<TextField
|
|
340
|
+
label='Query string parameter'
|
|
341
|
+
value={filter.queryParameter}
|
|
342
|
+
updateField={(_section, _subSection, _key, value) => updateFilterProp('queryParameter', value)}
|
|
343
|
+
/>
|
|
344
|
+
)}
|
|
345
|
+
<div className='bg-secondary-subtle p-2 my-2'>
|
|
346
|
+
<label>
|
|
347
|
+
<span>API Endpoint: </span>
|
|
348
|
+
<textarea value={filter?.apiFilter?.apiEndpoint || ''} disabled />
|
|
349
|
+
{isNestedDropdown && (
|
|
350
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
351
|
+
<Tooltip.Target>
|
|
352
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
353
|
+
</Tooltip.Target>
|
|
354
|
+
<Tooltip.Content>
|
|
355
|
+
<p>Your API Endpoint should return both value selector values.</p>
|
|
356
|
+
</Tooltip.Content>
|
|
357
|
+
</Tooltip>
|
|
358
|
+
)}
|
|
359
|
+
</label>
|
|
360
|
+
<div className={isNestedDropdown ? 'border border-dark p-1 my-1' : ''}>
|
|
361
|
+
<label>
|
|
362
|
+
<span>Value Selector: </span>
|
|
363
|
+
<input type='text' value={filter?.apiFilter?.valueSelector || ''} disabled />
|
|
364
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
365
|
+
<Tooltip.Target>
|
|
366
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
367
|
+
</Tooltip.Target>
|
|
368
|
+
<Tooltip.Content>
|
|
369
|
+
<p>Value to use in the html option element</p>
|
|
370
|
+
</Tooltip.Content>
|
|
371
|
+
</Tooltip>
|
|
372
|
+
<div>{` * Required`}</div>
|
|
373
|
+
</label>
|
|
374
|
+
<label>
|
|
375
|
+
<span>Display Text Selector: </span>
|
|
376
|
+
<input type='text' value={filter?.apiFilter?.textSelector || ''} disabled />
|
|
377
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
378
|
+
<Tooltip.Target>
|
|
379
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
380
|
+
</Tooltip.Target>
|
|
381
|
+
<Tooltip.Content>
|
|
382
|
+
<p>Text to use in the html option element. If none is applied value selector will be used.</p>
|
|
383
|
+
</Tooltip.Content>
|
|
384
|
+
</Tooltip>
|
|
385
|
+
<div>{` * Optional`}</div>
|
|
386
|
+
</label>
|
|
387
|
+
</div>
|
|
388
|
+
|
|
389
|
+
{isNestedDropdown && (
|
|
390
|
+
<div className={isNestedDropdown ? 'border border-dark p-1 my-1' : ''}>
|
|
391
|
+
<label>
|
|
392
|
+
<span>Subgroup Value Selector: </span>
|
|
393
|
+
<input value={filter?.apiFilter?.subgroupValueSelector || ''} disabled />
|
|
394
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
395
|
+
<Tooltip.Target>
|
|
396
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
397
|
+
</Tooltip.Target>
|
|
398
|
+
<Tooltip.Content>
|
|
399
|
+
<p>Value to use in the html option element</p>
|
|
400
|
+
</Tooltip.Content>
|
|
401
|
+
</Tooltip>
|
|
402
|
+
<div>{` * Required`}</div>
|
|
403
|
+
</label>
|
|
404
|
+
<label>
|
|
405
|
+
<span>Subgroup Display Text Selector: </span>
|
|
406
|
+
<input value={filter?.apifilter?.subgroupTextSelector || ''} disabled />
|
|
407
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
408
|
+
<Tooltip.Target>
|
|
409
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
410
|
+
</Tooltip.Target>
|
|
411
|
+
<Tooltip.Content>
|
|
412
|
+
<p>Text to use in the html option element. If none is applied value selector will be used.</p>
|
|
413
|
+
</Tooltip.Content>
|
|
414
|
+
</Tooltip>
|
|
415
|
+
<div>{` * Optional`}</div>
|
|
416
|
+
</label>
|
|
417
|
+
</div>
|
|
418
|
+
)}
|
|
419
|
+
|
|
420
|
+
<button
|
|
421
|
+
onClick={() => handleEditAPIValues(filter, isNestedDropdown, updateAPIFilter)}
|
|
422
|
+
className='btn btn-primary mt-2'
|
|
423
|
+
>
|
|
424
|
+
Edit API Values
|
|
425
|
+
</button>
|
|
426
|
+
</div>
|
|
427
|
+
|
|
428
|
+
<label>
|
|
429
|
+
<input
|
|
430
|
+
type='checkbox'
|
|
431
|
+
checked={useParameters}
|
|
432
|
+
aria-label='Create query parameters'
|
|
433
|
+
disabled={!filter.apiFilter?.valueSelector && !filter.apiFilter?.subgroupValueSelector}
|
|
434
|
+
onChange={e => toggleNestedQueryParameters(e.target.checked)}
|
|
435
|
+
/>
|
|
436
|
+
<span>
|
|
437
|
+
{' '}
|
|
438
|
+
Create query parameters{' '}
|
|
439
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
440
|
+
<Tooltip.Target>
|
|
441
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
442
|
+
</Tooltip.Target>
|
|
443
|
+
<Tooltip.Content>
|
|
444
|
+
<p>
|
|
445
|
+
Query parameters will be added to the URL which correspond to the respective value selector.
|
|
446
|
+
</p>
|
|
447
|
+
</Tooltip.Content>
|
|
448
|
+
</Tooltip>
|
|
449
|
+
</span>
|
|
450
|
+
</label>
|
|
451
|
+
|
|
452
|
+
{!!parentFilters.length && (
|
|
453
|
+
<label>
|
|
454
|
+
<span className='edit-label column-heading mt-1'>Parent Filter(s): </span>
|
|
455
|
+
<MultiSelect
|
|
456
|
+
label='Parent Filter(s): '
|
|
457
|
+
options={parentFilters.map(key => ({ value: key, label: key }))}
|
|
458
|
+
fieldName='parents'
|
|
459
|
+
selected={filter.parents}
|
|
460
|
+
updateField={(_section, _subsection, _fieldname, newItems) => {
|
|
461
|
+
updateFilterProp('parents', newItems)
|
|
462
|
+
}}
|
|
463
|
+
/>
|
|
464
|
+
</label>
|
|
465
|
+
)}
|
|
466
|
+
|
|
467
|
+
<label>
|
|
468
|
+
<span className='edit-label column-heading mt-1'>
|
|
469
|
+
Used By: (optional)
|
|
470
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
471
|
+
<Tooltip.Target>
|
|
472
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
473
|
+
</Tooltip.Target>
|
|
474
|
+
<Tooltip.Content>
|
|
475
|
+
<p>
|
|
476
|
+
Select if you would like specific visualizations or rows to use this filter. Otherwise the
|
|
477
|
+
filter will be added to all api requests.
|
|
478
|
+
</p>
|
|
479
|
+
</Tooltip.Content>
|
|
480
|
+
</Tooltip>
|
|
481
|
+
</span>
|
|
482
|
+
<MultiSelect
|
|
483
|
+
options={usedByOptions.map(opt => ({
|
|
484
|
+
value: opt,
|
|
485
|
+
label: usedByNameLookup[opt]
|
|
486
|
+
}))}
|
|
487
|
+
fieldName='usedBy'
|
|
488
|
+
selected={filter.usedBy}
|
|
489
|
+
updateField={(_section, _subsection, _fieldname, newItems) => {
|
|
490
|
+
updateFilterProp('usedBy', newItems)
|
|
491
|
+
}}
|
|
492
|
+
/>
|
|
493
|
+
</label>
|
|
494
|
+
|
|
495
|
+
<TextField
|
|
496
|
+
label='Reset Label: '
|
|
497
|
+
value={filter.resetLabel || ''}
|
|
498
|
+
updateField={(_section, _subSection, _key, value) => updateFilterProp('resetLabel', value)}
|
|
499
|
+
/>
|
|
500
|
+
</>
|
|
501
|
+
)}
|
|
502
|
+
|
|
503
|
+
{filter.type === 'datafilter' && (
|
|
504
|
+
<>
|
|
505
|
+
{filter.filterStyle !== FILTER_STYLE.nestedDropdown ? (
|
|
506
|
+
<>
|
|
507
|
+
<label>
|
|
508
|
+
<span className='edit-label column-heading'>Filter: </span>
|
|
509
|
+
<select
|
|
510
|
+
value={filter.columnName}
|
|
511
|
+
onChange={e => {
|
|
512
|
+
updateFilterProp('columnName', e.target.value)
|
|
513
|
+
}}
|
|
514
|
+
>
|
|
515
|
+
<option value=''>- Select Option -</option>
|
|
516
|
+
{columns.map(dataKey => (
|
|
517
|
+
<option value={dataKey} key={`filter-column-select-item-${dataKey}`}>
|
|
518
|
+
{dataKey}
|
|
519
|
+
</option>
|
|
520
|
+
))}
|
|
521
|
+
</select>
|
|
522
|
+
</label>
|
|
523
|
+
|
|
524
|
+
<Select
|
|
525
|
+
value={filter.defaultValue}
|
|
526
|
+
options={
|
|
527
|
+
filter.resetLabel
|
|
528
|
+
? [filter.resetLabel, ...config.dashboard.sharedFilters[filterIndex].values]
|
|
529
|
+
: config.dashboard.sharedFilters[filterIndex].values
|
|
530
|
+
}
|
|
531
|
+
updateField={(_section, _subSection, _key, value) => updateFilterProp('defaultValue', value)}
|
|
532
|
+
label={'Filter Default Value'}
|
|
533
|
+
initial={'Select'}
|
|
534
|
+
/>
|
|
535
|
+
|
|
536
|
+
<Select
|
|
537
|
+
value={filter.order || 'asc'}
|
|
538
|
+
options={filterOrderOptions}
|
|
539
|
+
updateField={(_section, _subSection, _key, value) => updateFilterProp('order', value)}
|
|
540
|
+
label={'Filter Order'}
|
|
541
|
+
/>
|
|
542
|
+
|
|
543
|
+
{/* if custom order is set use react-dnd library to sort the values */}
|
|
544
|
+
{filter.order === 'cust' && (
|
|
545
|
+
<FilterOrder
|
|
546
|
+
orderedValues={filter.orderedValues || filter.values}
|
|
547
|
+
handleFilterOrder={(index1, index2) => {
|
|
548
|
+
const values = [...filter.values]
|
|
549
|
+
const [removed] = values.splice(index1, 1)
|
|
550
|
+
values.splice(index2, 0, removed)
|
|
551
|
+
updateFilterProp('orderedValues', values)
|
|
552
|
+
}}
|
|
553
|
+
/>
|
|
554
|
+
)}
|
|
555
|
+
|
|
556
|
+
<label>
|
|
557
|
+
<span className='edit-label column-heading'>Show Dropdown</span>
|
|
558
|
+
<input
|
|
559
|
+
type='checkbox'
|
|
560
|
+
defaultChecked={filter.showDropdown === true}
|
|
561
|
+
onChange={e => {
|
|
562
|
+
updateFilterProp('showDropdown', !filter.showDropdown)
|
|
563
|
+
}}
|
|
564
|
+
/>
|
|
565
|
+
</label>
|
|
566
|
+
</>
|
|
567
|
+
) : (
|
|
568
|
+
<>
|
|
569
|
+
<NestedDropDownDashboard
|
|
570
|
+
filter={filter}
|
|
571
|
+
updateFilterProp={(name, value) => {
|
|
572
|
+
updateFilterProp(name, value)
|
|
573
|
+
}}
|
|
574
|
+
isDashboard={true}
|
|
575
|
+
config={config}
|
|
576
|
+
/>
|
|
577
|
+
<label>
|
|
578
|
+
<input
|
|
579
|
+
type='checkbox'
|
|
580
|
+
checked={useParameters}
|
|
581
|
+
aria-label='Create query parameters'
|
|
582
|
+
disabled={!filter.columnName || !filter.subGrouping?.columnName}
|
|
583
|
+
onChange={e => toggleNestedQueryParameters(e.target.checked)}
|
|
584
|
+
/>
|
|
585
|
+
<span>
|
|
586
|
+
{' '}
|
|
587
|
+
Create query parameters{' '}
|
|
588
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
589
|
+
<Tooltip.Target>
|
|
590
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
591
|
+
</Tooltip.Target>
|
|
592
|
+
<Tooltip.Content>
|
|
593
|
+
<p>
|
|
594
|
+
Query parameters will be added to the URL which correspond to the respective column name.
|
|
595
|
+
</p>
|
|
596
|
+
</Tooltip.Content>
|
|
597
|
+
</Tooltip>
|
|
598
|
+
</span>
|
|
599
|
+
</label>
|
|
600
|
+
</>
|
|
601
|
+
)}
|
|
602
|
+
<Select
|
|
603
|
+
label='Set By:'
|
|
604
|
+
value={filter.setBy}
|
|
605
|
+
options={Object.values(config.visualizations)
|
|
606
|
+
.filter(viz => viz.type !== 'dashboardFilters')
|
|
607
|
+
.map(viz => ({
|
|
608
|
+
value: viz.uid,
|
|
609
|
+
label: getVizTitle(viz, viz.type)
|
|
610
|
+
}))}
|
|
611
|
+
updateField={(_section, _subSection, _key, value) => updateFilterProp('setBy', value)}
|
|
612
|
+
initial='- Select Option -'
|
|
613
|
+
/>
|
|
614
|
+
<label>
|
|
615
|
+
<span className='edit-label column-heading mt-1'>
|
|
616
|
+
Used By: (optional)
|
|
617
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
618
|
+
<Tooltip.Target>
|
|
619
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
620
|
+
</Tooltip.Target>
|
|
621
|
+
<Tooltip.Content>
|
|
622
|
+
<p>
|
|
623
|
+
Select if you would like specific visualizations or rows to use this filter. Otherwise the
|
|
624
|
+
filter will be added to all api requests.
|
|
625
|
+
</p>
|
|
626
|
+
</Tooltip.Content>
|
|
627
|
+
</Tooltip>
|
|
628
|
+
</span>
|
|
629
|
+
<MultiSelect
|
|
630
|
+
options={usedByOptions.map(opt => ({
|
|
631
|
+
value: opt,
|
|
632
|
+
label: usedByNameLookup[opt]
|
|
633
|
+
}))}
|
|
634
|
+
fieldName='usedBy'
|
|
635
|
+
selected={filter.usedBy}
|
|
636
|
+
updateField={(_section, _subsection, _fieldname, newItems) => {
|
|
637
|
+
updateFilterProp('usedBy', newItems)
|
|
638
|
+
}}
|
|
639
|
+
/>
|
|
640
|
+
</label>
|
|
641
|
+
<TextField
|
|
642
|
+
label='Reset Label: '
|
|
643
|
+
value={filter.resetLabel || ''}
|
|
644
|
+
updateField={(_section, _subSection, _key, value) => updateFilterProp('resetLabel', value)}
|
|
645
|
+
/>
|
|
646
|
+
|
|
647
|
+
<label>
|
|
648
|
+
<span className='edit-label column-heading'>Parent Filter: </span>
|
|
649
|
+
<select
|
|
650
|
+
value={filter.parents || []}
|
|
651
|
+
onChange={e => {
|
|
652
|
+
updateFilterProp('parents', e.target.value)
|
|
653
|
+
}}
|
|
654
|
+
>
|
|
655
|
+
<option value=''>Select a filter</option>
|
|
656
|
+
{config.dashboard.sharedFilters &&
|
|
657
|
+
config.dashboard.sharedFilters.map(sharedFilter => {
|
|
658
|
+
if (sharedFilter.key !== filter.key) {
|
|
659
|
+
return <option key={sharedFilter.key}>{sharedFilter.key}</option>
|
|
660
|
+
}
|
|
661
|
+
})}
|
|
662
|
+
</select>
|
|
663
|
+
</label>
|
|
664
|
+
|
|
665
|
+
{!isNestedDropdown && (
|
|
666
|
+
<TextField
|
|
667
|
+
label='Default Value Set By Query String Parameter: '
|
|
668
|
+
value={filter.setByQueryParameter || ''}
|
|
669
|
+
updateField={(_section, _subSection, _key, value) => updateFilterProp('setByQueryParameter', value)}
|
|
670
|
+
/>
|
|
671
|
+
)}
|
|
672
|
+
</>
|
|
673
|
+
)}
|
|
674
|
+
</>
|
|
675
|
+
)}
|
|
676
|
+
</>
|
|
677
|
+
)
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
export default FilterEditor
|