@cdc/dashboard 4.23.5 → 4.23.7
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/cdcdashboard.js +76291 -73619
- package/examples/default-filter-control.json +3 -0
- package/examples/shared-filters.json +602 -0
- package/index.html +2 -1
- package/package.json +9 -9
- package/src/CdcDashboard.jsx +56 -30
- package/src/components/DataTable.tsx +4 -4
- package/src/components/Header.jsx +166 -150
- package/src/components/Widget.jsx +61 -6
- package/src/scss/main.scss +5 -7
- package/LICENSE +0 -201
package/src/CdcDashboard.jsx
CHANGED
|
@@ -31,10 +31,11 @@ import Header from './components/Header'
|
|
|
31
31
|
import defaults from './data/initial-state'
|
|
32
32
|
import Widget from './components/Widget'
|
|
33
33
|
import DataTable from './components/DataTable'
|
|
34
|
-
import
|
|
34
|
+
import MediaControls from '@cdc/core/components/MediaControls'
|
|
35
35
|
|
|
36
36
|
import './scss/main.scss'
|
|
37
37
|
import '@cdc/core/styles/v2/main.scss'
|
|
38
|
+
import AdvancedEditor from '@cdc/core/components/AdvancedEditor'
|
|
38
39
|
|
|
39
40
|
/* eslint-disable react-hooks/exhaustive-deps */
|
|
40
41
|
|
|
@@ -75,7 +76,7 @@ const addVisualization = (type, subType) => {
|
|
|
75
76
|
return newVisualizationConfig
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
const VisualizationsPanel = () => (
|
|
79
|
+
const VisualizationsPanel = ({ loadConfig, config }) => (
|
|
79
80
|
<div className='visualizations-panel'>
|
|
80
81
|
<p style={{ fontSize: '14px' }}>Click and drag an item onto the grid to add it to your dashboard.</p>
|
|
81
82
|
<span className='subheading-3'>Chart</span>
|
|
@@ -96,7 +97,10 @@ const VisualizationsPanel = () => (
|
|
|
96
97
|
<Widget addVisualization={() => addVisualization('waffle-chart', '')} type='waffle-chart' />
|
|
97
98
|
<Widget addVisualization={() => addVisualization('markup-include', '')} type='markup-include' />
|
|
98
99
|
<Widget addVisualization={() => addVisualization('filtered-text', '')} type='filtered-text' />
|
|
100
|
+
<Widget addVisualization={() => addVisualization('filter-dropdowns', '')} type='filter-dropdowns' />
|
|
99
101
|
</div>
|
|
102
|
+
<span className='subheading-3'>Advanced</span>
|
|
103
|
+
<AdvancedEditor loadConfig={loadConfig} state={config} />
|
|
100
104
|
</div>
|
|
101
105
|
)
|
|
102
106
|
|
|
@@ -268,7 +272,6 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
|
|
|
268
272
|
}
|
|
269
273
|
|
|
270
274
|
setData(datasets)
|
|
271
|
-
|
|
272
275
|
updateConfig(newConfig, datasets)
|
|
273
276
|
setLoading(false)
|
|
274
277
|
}
|
|
@@ -281,6 +284,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
|
|
|
281
284
|
let add = true
|
|
282
285
|
|
|
283
286
|
filters.forEach(filter => {
|
|
287
|
+
// eslint-disable-next-line eqeqeq
|
|
284
288
|
if (filter.type !== 'url' && row[filter.columnName] != filter.active) {
|
|
285
289
|
add = false
|
|
286
290
|
}
|
|
@@ -375,7 +379,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
|
|
|
375
379
|
if (applicableFilters.length > 0) {
|
|
376
380
|
const visualization = newConfig.visualizations[visualizationKey]
|
|
377
381
|
|
|
378
|
-
const formattedData = getFormattedData(visualization.data, visualization.dataDescription)
|
|
382
|
+
const formattedData = getFormattedData(newConfig.datasets[visualization.dataKey] && newConfig.datasets[visualization.dataKey].data ? newConfig.datasets[visualization.dataKey].data : visualization.data, visualization.dataDescription)
|
|
379
383
|
|
|
380
384
|
newFilteredData[visualizationKey] = filterData(applicableFilters, formattedData || visualization.data || (dataOverride || data)[visualization.dataKey])
|
|
381
385
|
}
|
|
@@ -414,7 +418,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
|
|
|
414
418
|
setConfig(updatedConfig)
|
|
415
419
|
}
|
|
416
420
|
|
|
417
|
-
const Filters = () => {
|
|
421
|
+
const Filters = ({hide}) => {
|
|
418
422
|
const changeFilterActive = (index, value) => {
|
|
419
423
|
let dashboardConfig = { ...config.dashboard }
|
|
420
424
|
|
|
@@ -435,15 +439,26 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
|
|
|
435
439
|
})
|
|
436
440
|
|
|
437
441
|
setFilteredData(newFilteredData)
|
|
442
|
+
if (dashboardConfig.sharedFilters[index].active === dashboardConfig.sharedFilters[index].resetLabel) {
|
|
443
|
+
setFilteredData(data)
|
|
444
|
+
}
|
|
438
445
|
}
|
|
439
446
|
|
|
440
447
|
const announceChange = text => {}
|
|
441
448
|
|
|
442
449
|
return config.dashboard.sharedFilters.map((singleFilter, index) => {
|
|
443
|
-
if (singleFilter.type !== 'url' && !singleFilter.showDropdown) return <></>
|
|
450
|
+
if ((singleFilter.type !== 'url' && !singleFilter.showDropdown) || (hide && hide.indexOf(index) !== -1)) return <></>
|
|
444
451
|
|
|
445
452
|
const values = []
|
|
446
453
|
|
|
454
|
+
if (singleFilter.resetLabel) {
|
|
455
|
+
values.push(
|
|
456
|
+
<option key={`${singleFilter.resetLabel}-option-${index}`} value={singleFilter.resetLabel}>
|
|
457
|
+
{singleFilter.resetLabel}
|
|
458
|
+
</option>
|
|
459
|
+
)
|
|
460
|
+
}
|
|
461
|
+
|
|
447
462
|
singleFilter.values.forEach((filterOption, index) => {
|
|
448
463
|
values.push(
|
|
449
464
|
<option key={`${singleFilter.key}-option-${index}`} value={filterOption}>
|
|
@@ -453,21 +468,23 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
|
|
|
453
468
|
})
|
|
454
469
|
|
|
455
470
|
return (
|
|
456
|
-
<
|
|
457
|
-
<
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
+
<div className='cove-dashboard-filters'>
|
|
472
|
+
<section className='dashboard-filters-section' key={`${singleFilter.key}-filtersection-${index}`}>
|
|
473
|
+
<label htmlFor={`filter-${index}`}>{singleFilter.key}</label>
|
|
474
|
+
<select
|
|
475
|
+
id={`filter-${index}`}
|
|
476
|
+
className='filter-select'
|
|
477
|
+
data-index='0'
|
|
478
|
+
value={singleFilter.active}
|
|
479
|
+
onChange={val => {
|
|
480
|
+
changeFilterActive(index, val.target.value)
|
|
481
|
+
announceChange(`Filter ${singleFilter.key} value has been changed to ${val.target.value}, please reference the data table to see updated values.`)
|
|
482
|
+
}}
|
|
483
|
+
>
|
|
484
|
+
{values}
|
|
485
|
+
</select>
|
|
486
|
+
</section>
|
|
487
|
+
</div>
|
|
471
488
|
)
|
|
472
489
|
})
|
|
473
490
|
}
|
|
@@ -538,7 +555,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
|
|
|
538
555
|
body = (
|
|
539
556
|
<>
|
|
540
557
|
<Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor='Chart' />
|
|
541
|
-
<CdcChart key={visualizationKey} config={visualizationConfig} isEditor={true} isDebug={isDebug} setConfig={updateConfig} setSharedFilter={setsSharedFilter ? setSharedFilter : undefined} isDashboard={true} />
|
|
558
|
+
<CdcChart key={visualizationKey} config={visualizationConfig} isEditor={true} isDebug={isDebug} setConfig={updateConfig} setSharedFilter={setsSharedFilter ? setSharedFilter : undefined} setSharedFilterValue={setSharedFilterValue} dashboardConfig={config} isDashboard={true} />
|
|
542
559
|
</>
|
|
543
560
|
)
|
|
544
561
|
break
|
|
@@ -583,6 +600,14 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
|
|
|
583
600
|
</>
|
|
584
601
|
)
|
|
585
602
|
break
|
|
603
|
+
case 'filter-dropdowns':
|
|
604
|
+
body = (
|
|
605
|
+
<>
|
|
606
|
+
<Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor='Filter Dropdowns' />
|
|
607
|
+
<Filters hide={visualizationConfig.hide} />
|
|
608
|
+
</>
|
|
609
|
+
)
|
|
610
|
+
break
|
|
586
611
|
default:
|
|
587
612
|
body = <></>
|
|
588
613
|
break
|
|
@@ -595,7 +620,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
|
|
|
595
620
|
<DndProvider backend={HTML5Backend}>
|
|
596
621
|
<Header tabSelected={tabSelected} setTabSelected={setTabSelected} preview={preview} setPreview={setPreview} />
|
|
597
622
|
<div className='layout-container'>
|
|
598
|
-
<VisualizationsPanel />
|
|
623
|
+
<VisualizationsPanel loadConfig={loadConfig} config={config} />
|
|
599
624
|
<Grid />
|
|
600
625
|
</div>
|
|
601
626
|
</DndProvider>
|
|
@@ -615,11 +640,8 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
|
|
|
615
640
|
{/* Description */}
|
|
616
641
|
{description && <div className='subtext'>{parse(description)}</div>}
|
|
617
642
|
{/* Filters */}
|
|
618
|
-
{config.dashboard.sharedFilters && (
|
|
619
|
-
<
|
|
620
|
-
{' '}
|
|
621
|
-
<Filters />
|
|
622
|
-
</div>
|
|
643
|
+
{config.dashboard.sharedFilters && Object.keys(config.visualizations).filter(vizKey => config.visualizations[vizKey].visualizationType === 'filter-dropdowns').length === 0 && (
|
|
644
|
+
<Filters />
|
|
623
645
|
)}
|
|
624
646
|
|
|
625
647
|
{/* Visualizations */}
|
|
@@ -666,6 +688,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
|
|
|
666
688
|
<CdcChart
|
|
667
689
|
key={col.widget}
|
|
668
690
|
config={visualizationConfig}
|
|
691
|
+
dashboardConfig={config}
|
|
669
692
|
isEditor={false}
|
|
670
693
|
setConfig={newConfig => {
|
|
671
694
|
updateChildConfig(col.widget, newConfig)
|
|
@@ -734,6 +757,9 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
|
|
|
734
757
|
isDashboard={true}
|
|
735
758
|
/>
|
|
736
759
|
)}
|
|
760
|
+
{visualizationConfig.type === 'filter-dropdowns' && (
|
|
761
|
+
<Filters hide={visualizationConfig.hide} />
|
|
762
|
+
)}
|
|
737
763
|
</div>
|
|
738
764
|
</React.Fragment>
|
|
739
765
|
)
|
|
@@ -746,8 +772,8 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
|
|
|
746
772
|
|
|
747
773
|
{/* Image or PDF Inserts */}
|
|
748
774
|
<section className='download-buttons'>
|
|
749
|
-
{config.table.downloadImageButton && <
|
|
750
|
-
{config.table.downloadPdfButton && <
|
|
775
|
+
{config.table.downloadImageButton && <MediaControls.Button title='Download Dashboard as Image' type='image' state={config} text='Download Dashboard Image' elementToCapture={imageId} />}
|
|
776
|
+
{config.table.downloadPdfButton && <MediaControls.Button title='Download Dashboard as PDF' type='pdf' state={config} text='Download Dashboard PDF' elementToCapture={imageId} />}
|
|
751
777
|
</section>
|
|
752
778
|
|
|
753
779
|
{/* Data Table */}
|
|
@@ -2,7 +2,7 @@ import React, { useEffect, useState, useMemo, memo } from 'react'
|
|
|
2
2
|
import { useTable, useSortBy, useResizeColumns, useBlockLayout } from 'react-table'
|
|
3
3
|
import Papa from 'papaparse'
|
|
4
4
|
import { Base64 } from 'js-base64'
|
|
5
|
-
import
|
|
5
|
+
import MediaControls from '@cdc/core/components/MediaControls'
|
|
6
6
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
7
7
|
|
|
8
8
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
@@ -94,7 +94,7 @@ export default function DataTable(props) {
|
|
|
94
94
|
|
|
95
95
|
return (
|
|
96
96
|
<ErrorBoundary component='DataTable'>
|
|
97
|
-
<
|
|
97
|
+
<MediaControls.Section classes={['download-links']}>
|
|
98
98
|
{config.table.showDownloadUrl && dataFileSourceType === 'url' && (
|
|
99
99
|
<a className='dashboard-download-link' href={config.datasets[datasetKey].dataFileName} title='Link to View Dataset' target='_blank'>
|
|
100
100
|
{' '}
|
|
@@ -103,7 +103,7 @@ export default function DataTable(props) {
|
|
|
103
103
|
</a>
|
|
104
104
|
)}
|
|
105
105
|
{config.table.download && <DownloadButton data={data} />}
|
|
106
|
-
</
|
|
106
|
+
</MediaControls.Section>
|
|
107
107
|
{config.table.show && (
|
|
108
108
|
<section className={`data-table-container`} aria-label={accessibilityLabel}>
|
|
109
109
|
<div
|
|
@@ -119,7 +119,7 @@ export default function DataTable(props) {
|
|
|
119
119
|
}
|
|
120
120
|
}}
|
|
121
121
|
>
|
|
122
|
-
<Icon display={tableExpanded ? 'minus' : 'plus'} base/>
|
|
122
|
+
<Icon display={tableExpanded ? 'minus' : 'plus'} base />
|
|
123
123
|
{config.table.label}
|
|
124
124
|
{datasetKey ? `: ${datasetKey}` : ''}
|
|
125
125
|
</div>
|
|
@@ -45,17 +45,31 @@ const Header = ({ setPreview, tabSelected, setTabSelected, back, subEditor = nul
|
|
|
45
45
|
|
|
46
46
|
const removeFilter = index => {
|
|
47
47
|
let dashboardConfig = { ...config.dashboard }
|
|
48
|
+
let visualizations = { ...config.visualizations }
|
|
48
49
|
|
|
49
50
|
dashboardConfig.sharedFilters.splice(index, 1)
|
|
50
51
|
|
|
52
|
+
Object.keys(visualizations).forEach(vizKey => {
|
|
53
|
+
if(visualizations[vizKey].visualizationType === 'filter-dropdowns' && visualizations[vizKey].hide && visualizations[vizKey].hide.length > 0){
|
|
54
|
+
if(visualizations[vizKey].hide.indexOf(index) !== -1){
|
|
55
|
+
visualizations[vizKey].hide.splice(visualizations[vizKey].hide.indexOf(index), 1)
|
|
56
|
+
}
|
|
57
|
+
visualizations[vizKey].hide.forEach((hideIndex, i) => {
|
|
58
|
+
if(hideIndex > index){
|
|
59
|
+
visualizations[vizKey].hide[i] = hideIndex - 1
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
|
|
51
65
|
// Ensures URL filters refresh after filter removal
|
|
52
|
-
if(dashboardConfig.datasets){
|
|
66
|
+
if (dashboardConfig.datasets) {
|
|
53
67
|
Object.keys(dashboardConfig.datasets).forEach(datasetKey => {
|
|
54
68
|
delete dashboardConfig.datasets[datasetKey].runtimeDataUrl
|
|
55
69
|
})
|
|
56
70
|
}
|
|
57
71
|
|
|
58
|
-
updateConfig({ ...config, dashboard: dashboardConfig })
|
|
72
|
+
updateConfig({ ...config, visualizations, dashboard: dashboardConfig })
|
|
59
73
|
|
|
60
74
|
overlay?.actions.toggleOverlay()
|
|
61
75
|
}
|
|
@@ -165,11 +179,10 @@ const Header = ({ setPreview, tabSelected, setTabSelected, back, subEditor = nul
|
|
|
165
179
|
|
|
166
180
|
newLabels[value] = e.target.value
|
|
167
181
|
|
|
168
|
-
|
|
169
182
|
updateFilterProp('labels', index, newLabels)
|
|
170
183
|
}
|
|
171
184
|
|
|
172
|
-
const removeValue =
|
|
185
|
+
const removeValue = valueIndex => {
|
|
173
186
|
let newLabels = filter.labels || {}
|
|
174
187
|
let newValues = filter.values || []
|
|
175
188
|
|
|
@@ -183,7 +196,7 @@ const Header = ({ setPreview, tabSelected, setTabSelected, back, subEditor = nul
|
|
|
183
196
|
})
|
|
184
197
|
}
|
|
185
198
|
|
|
186
|
-
const addNewValue =
|
|
199
|
+
const addNewValue = e => {
|
|
187
200
|
e.preventDefault()
|
|
188
201
|
if (!filter.values || filter.values.indexOf(e.target[0].value) === -1) {
|
|
189
202
|
let newValues = filter.values || []
|
|
@@ -216,146 +229,149 @@ const Header = ({ setPreview, tabSelected, setTabSelected, back, subEditor = nul
|
|
|
216
229
|
Remove Filter
|
|
217
230
|
</button>
|
|
218
231
|
<label>
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
{filter.type === 'url' &&
|
|
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
|
-
value={filter.labels ? filter.labels[value] : undefined}
|
|
265
|
-
onChange={(e) => updateLabel(e, value)}
|
|
266
|
-
/>
|
|
267
|
-
<button
|
|
268
|
-
onClick={() => removeValue(valueIndex)}
|
|
269
|
-
>
|
|
270
|
-
X
|
|
271
|
-
</button>
|
|
272
|
-
</li>
|
|
273
|
-
))}
|
|
274
|
-
</ul>
|
|
275
|
-
<form
|
|
276
|
-
onSubmit={addNewValue}
|
|
277
|
-
>
|
|
278
|
-
<input type='text' /> <button type='submit'>Add New Value</button>
|
|
279
|
-
</form>
|
|
280
|
-
</>}
|
|
281
|
-
{filter.type !== 'url' && <>
|
|
282
|
-
<label>
|
|
283
|
-
<span className='edit-label column-heading'>Filter: </span>
|
|
284
|
-
<select
|
|
285
|
-
value={filter.columnName}
|
|
286
|
-
onChange={e => {
|
|
287
|
-
updateFilterProp('columnName', index, e.target.value)
|
|
288
|
-
}}
|
|
289
|
-
>
|
|
290
|
-
<option value=''>- Select Option -</option>
|
|
291
|
-
{columns.map(dataKey => (
|
|
292
|
-
<option value={dataKey} key={`filter-column-select-item-${dataKey}`}>
|
|
293
|
-
{dataKey}
|
|
294
|
-
</option>
|
|
295
|
-
))}
|
|
296
|
-
</select>
|
|
297
|
-
</label>
|
|
298
|
-
<label>
|
|
299
|
-
<span className='edit-label column-heading'>Label: </span>
|
|
300
|
-
<input
|
|
301
|
-
type='text'
|
|
302
|
-
value={filter.key}
|
|
303
|
-
onChange={e => {
|
|
304
|
-
updateFilterProp('key', index, e.target.value)
|
|
305
|
-
}}
|
|
306
|
-
/>
|
|
307
|
-
</label>
|
|
308
|
-
<label>
|
|
309
|
-
<span className='edit-label column-heading'>Show Dropdown</span>
|
|
310
|
-
<input
|
|
311
|
-
type='checkbox'
|
|
312
|
-
defaultChecked={filter.showDropdown === true}
|
|
313
|
-
onChange={e => {
|
|
314
|
-
updateFilterProp('showDropdown', index, !filter.showDropdown)
|
|
315
|
-
}}
|
|
316
|
-
/>
|
|
317
|
-
</label>
|
|
318
|
-
<label>
|
|
319
|
-
<span className='edit-label column-heading'>Set By: </span>
|
|
320
|
-
<select value={filter.setBy} onChange={e => updateFilterProp('setBy', index, e.target.value)}>
|
|
321
|
-
<option value=''>- Select Option -</option>
|
|
322
|
-
{Object.keys(config.visualizations).map(vizKey => (
|
|
323
|
-
<option value={vizKey} key={`set-by-select-item-${vizKey}`}>
|
|
324
|
-
{config.visualizations[vizKey].general && config.visualizations[vizKey].general.title ? config.visualizations[vizKey].general.title : config.visualizations[vizKey].title || vizKey}
|
|
325
|
-
</option>
|
|
326
|
-
))}
|
|
327
|
-
</select>
|
|
328
|
-
</label>
|
|
329
|
-
<label>
|
|
330
|
-
<span className='edit-label column-heading'>Used By:</span>
|
|
331
|
-
<ul>
|
|
332
|
-
{filter.usedBy &&
|
|
333
|
-
filter.usedBy.map(vizKey => (
|
|
334
|
-
<li key={`used-by-list-item-${vizKey}`}>
|
|
335
|
-
<span>{config.visualizations[vizKey].general && config.visualizations[vizKey].general.title ? config.visualizations[vizKey].general.title : config.visualizations[vizKey].title || vizKey}</span>{' '}
|
|
336
|
-
<button
|
|
337
|
-
onClick={e => {
|
|
338
|
-
e.preventDefault()
|
|
339
|
-
removeFilterUsedBy(filter, index, vizKey)
|
|
340
|
-
}}
|
|
341
|
-
>
|
|
342
|
-
X
|
|
343
|
-
</button>
|
|
232
|
+
<span className='edit-label column-heading'>Filter Type:</span>
|
|
233
|
+
<select defaultValue={filter.type || 'data'} onChange={e => updateFilterProp('type', index, e.target.value)}>
|
|
234
|
+
<option value='url'>URL</option>
|
|
235
|
+
<option value='data'>Data</option>
|
|
236
|
+
</select>
|
|
237
|
+
</label>
|
|
238
|
+
{filter.type === 'url' && (
|
|
239
|
+
<>
|
|
240
|
+
<label>
|
|
241
|
+
<span className='edit-label column-heading'>Label: </span>
|
|
242
|
+
<input
|
|
243
|
+
type='text'
|
|
244
|
+
value={filter.key}
|
|
245
|
+
onChange={e => {
|
|
246
|
+
updateFilterProp('key', index, e.target.value)
|
|
247
|
+
}}
|
|
248
|
+
/>
|
|
249
|
+
</label>
|
|
250
|
+
<label>
|
|
251
|
+
<span className='edit-label column-heading'>URL to Filter: </span>
|
|
252
|
+
<select defaultValue={filter.datasetKey || ''} onChange={e => updateFilterProp('datasetKey', index, e.target.value)}>
|
|
253
|
+
<option value=''>- Select Option -</option>
|
|
254
|
+
{Object.keys(config.datasets).map(datasetKey => {
|
|
255
|
+
if (config.datasets[datasetKey].dataUrl) {
|
|
256
|
+
return (
|
|
257
|
+
<option key={datasetKey} value={datasetKey}>
|
|
258
|
+
{config.datasets[datasetKey].dataUrl.substring(0, 50)}
|
|
259
|
+
</option>
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
return <React.Fragment key={datasetKey}></React.Fragment>
|
|
263
|
+
})}
|
|
264
|
+
</select>
|
|
265
|
+
</label>
|
|
266
|
+
<label>
|
|
267
|
+
<span className='edit-label column-heading'>Query string parameter</span> <input type='text' defaultValue={filter.queryParameter} onChange={e => updateFilterProp('queryParameter', index, e.target.value)} />
|
|
268
|
+
</label>
|
|
269
|
+
<span className='edit-label column-heading'>Values</span>{' '}
|
|
270
|
+
<ul className='value-list'>
|
|
271
|
+
{filter.values &&
|
|
272
|
+
filter.values.map((value, valueIndex) => (
|
|
273
|
+
<li>
|
|
274
|
+
{value}
|
|
275
|
+
<input type='text' value={filter.labels ? filter.labels[value] : undefined} onChange={e => updateLabel(e, value)} />
|
|
276
|
+
<button onClick={() => removeValue(valueIndex)}>X</button>
|
|
344
277
|
</li>
|
|
345
278
|
))}
|
|
346
279
|
</ul>
|
|
347
|
-
<
|
|
348
|
-
<
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
280
|
+
<form onSubmit={addNewValue}>
|
|
281
|
+
<input type='text' /> <button type='submit'>Add New Value</button>
|
|
282
|
+
</form>
|
|
283
|
+
</>
|
|
284
|
+
)}
|
|
285
|
+
{filter.type !== 'url' && (
|
|
286
|
+
<>
|
|
287
|
+
<label>
|
|
288
|
+
<span className='edit-label column-heading'>Filter: </span>
|
|
289
|
+
<select
|
|
290
|
+
value={filter.columnName}
|
|
291
|
+
onChange={e => {
|
|
292
|
+
updateFilterProp('columnName', index, e.target.value)
|
|
293
|
+
}}
|
|
294
|
+
>
|
|
295
|
+
<option value=''>- Select Option -</option>
|
|
296
|
+
{columns.map(dataKey => (
|
|
297
|
+
<option value={dataKey} key={`filter-column-select-item-${dataKey}`}>
|
|
298
|
+
{dataKey}
|
|
299
|
+
</option>
|
|
300
|
+
))}
|
|
301
|
+
</select>
|
|
302
|
+
</label>
|
|
303
|
+
<label>
|
|
304
|
+
<span className='edit-label column-heading'>Label: </span>
|
|
305
|
+
<input
|
|
306
|
+
type='text'
|
|
307
|
+
value={filter.key}
|
|
308
|
+
onChange={e => {
|
|
309
|
+
updateFilterProp('key', index, e.target.value)
|
|
310
|
+
}}
|
|
311
|
+
/>
|
|
312
|
+
</label>
|
|
313
|
+
<label>
|
|
314
|
+
<span className='edit-label column-heading'>Show Dropdown</span>
|
|
315
|
+
<input
|
|
316
|
+
type='checkbox'
|
|
317
|
+
defaultChecked={filter.showDropdown === true}
|
|
318
|
+
onChange={e => {
|
|
319
|
+
updateFilterProp('showDropdown', index, !filter.showDropdown)
|
|
320
|
+
}}
|
|
321
|
+
/>
|
|
322
|
+
</label>
|
|
323
|
+
<label>
|
|
324
|
+
<span className='edit-label column-heading'>Set By: </span>
|
|
325
|
+
<select value={filter.setBy} onChange={e => updateFilterProp('setBy', index, e.target.value)}>
|
|
326
|
+
<option value=''>- Select Option -</option>
|
|
327
|
+
{Object.keys(config.visualizations).map(vizKey => (
|
|
328
|
+
<option value={vizKey} key={`set-by-select-item-${vizKey}`}>
|
|
353
329
|
{config.visualizations[vizKey].general && config.visualizations[vizKey].general.title ? config.visualizations[vizKey].general.title : config.visualizations[vizKey].title || vizKey}
|
|
354
330
|
</option>
|
|
355
331
|
))}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
332
|
+
</select>
|
|
333
|
+
</label>
|
|
334
|
+
<label>
|
|
335
|
+
<span className='edit-label column-heading'>Used By:</span>
|
|
336
|
+
<ul>
|
|
337
|
+
{filter.usedBy &&
|
|
338
|
+
filter.usedBy.map(vizKey => (
|
|
339
|
+
<li key={`used-by-list-item-${vizKey}`}>
|
|
340
|
+
<span>{config.visualizations[vizKey].general && config.visualizations[vizKey].general.title ? config.visualizations[vizKey].general.title : config.visualizations[vizKey].title || vizKey}</span>{' '}
|
|
341
|
+
<button
|
|
342
|
+
onClick={e => {
|
|
343
|
+
e.preventDefault()
|
|
344
|
+
removeFilterUsedBy(filter, index, vizKey)
|
|
345
|
+
}}
|
|
346
|
+
>
|
|
347
|
+
X
|
|
348
|
+
</button>
|
|
349
|
+
</li>
|
|
350
|
+
))}
|
|
351
|
+
</ul>
|
|
352
|
+
<select onChange={e => addFilterUsedBy(filter, index, e.target.value)}>
|
|
353
|
+
<option value=''>- Select Option -</option>
|
|
354
|
+
{Object.keys(config.visualizations)
|
|
355
|
+
.filter(vizKey => filter.setBy !== vizKey && (!filter.usedBy || filter.usedBy.indexOf(vizKey) === -1) && !config.visualizations[vizKey].usesSharedFilter)
|
|
356
|
+
.map(vizKey => (
|
|
357
|
+
<option value={vizKey} key={`used-by-select-item-${vizKey}`}>
|
|
358
|
+
{config.visualizations[vizKey].general && config.visualizations[vizKey].general.title ? config.visualizations[vizKey].general.title : config.visualizations[vizKey].title || vizKey}
|
|
359
|
+
</option>
|
|
360
|
+
))}
|
|
361
|
+
</select>
|
|
362
|
+
</label>
|
|
363
|
+
<label>
|
|
364
|
+
<span className='edit-label column-heading'>Reset Label: </span>
|
|
365
|
+
<input
|
|
366
|
+
type='text'
|
|
367
|
+
value={filter.resetLabel ? filter.resetLabel : ''}
|
|
368
|
+
onChange={e => {
|
|
369
|
+
updateFilterProp('resetLabel', index, e.target.value)
|
|
370
|
+
}}
|
|
371
|
+
/>
|
|
372
|
+
</label>
|
|
373
|
+
</>
|
|
374
|
+
)}
|
|
359
375
|
</fieldset>
|
|
360
376
|
<button type='button' className='btn btn-primary' style={{ display: 'inline-block', 'margin-right': '1em' }} onClick={overlay?.actions.toggleOverlay}>
|
|
361
377
|
Cancel
|
|
@@ -382,7 +398,7 @@ const Header = ({ setPreview, tabSelected, setTabSelected, back, subEditor = nul
|
|
|
382
398
|
</div>
|
|
383
399
|
)}
|
|
384
400
|
{!subEditor && (
|
|
385
|
-
<div className=
|
|
401
|
+
<div className='toggle-bar__wrapper'>
|
|
386
402
|
<ul className='toggle-bar'>
|
|
387
403
|
<li
|
|
388
404
|
className={tabSelected === 0 ? 'active' : 'inactive'}
|
|
@@ -441,17 +457,18 @@ const Header = ({ setPreview, tabSelected, setTabSelected, back, subEditor = nul
|
|
|
441
457
|
)}
|
|
442
458
|
{tabSelected === 2 && (
|
|
443
459
|
<>
|
|
444
|
-
|
|
445
|
-
<div className="wrap">
|
|
460
|
+
<div className='wrap'>
|
|
446
461
|
<label>
|
|
447
462
|
<input type='checkbox' defaultChecked={config.table.show} onChange={e => changeConfigValue('table', 'show', e.target.checked)} />
|
|
448
463
|
Show Data Table(s)
|
|
449
|
-
</label
|
|
464
|
+
</label>
|
|
465
|
+
<br />
|
|
450
466
|
|
|
451
467
|
<label>
|
|
452
468
|
<input type='checkbox' defaultChecked={config.table.expanded} onChange={e => changeConfigValue('table', 'expanded', e.target.checked)} />
|
|
453
469
|
Expanded by Default
|
|
454
|
-
</label
|
|
470
|
+
</label>
|
|
471
|
+
<br />
|
|
455
472
|
</div>
|
|
456
473
|
|
|
457
474
|
{/* <div className="wrap">
|
|
@@ -465,7 +482,7 @@ const Header = ({ setPreview, tabSelected, setTabSelected, back, subEditor = nul
|
|
|
465
482
|
</label>
|
|
466
483
|
</div> */}
|
|
467
484
|
|
|
468
|
-
<div className=
|
|
485
|
+
<div className='wrap'>
|
|
469
486
|
<label>
|
|
470
487
|
<input type='checkbox' defaultChecked={config.table.limitHeight} onChange={e => changeConfigValue('table', 'limitHeight', e.target.checked)} />
|
|
471
488
|
Limit Table Height
|
|
@@ -473,7 +490,7 @@ const Header = ({ setPreview, tabSelected, setTabSelected, back, subEditor = nul
|
|
|
473
490
|
{config.table.limitHeight && <input class='table-height-input' type='text' placeholder='Height (px)' defaultValue={config.table.height} onChange={e => changeConfigValue('table', 'height', e.target.value)} />}
|
|
474
491
|
</div>
|
|
475
492
|
|
|
476
|
-
<div className=
|
|
493
|
+
<div className='wrap'>
|
|
477
494
|
<label>
|
|
478
495
|
<input type='checkbox' defaultChecked={config.table.download} onChange={e => changeConfigValue('table', 'download', e.target.checked)} />
|
|
479
496
|
Show Download CSV Link
|
|
@@ -486,10 +503,9 @@ const Header = ({ setPreview, tabSelected, setTabSelected, back, subEditor = nul
|
|
|
486
503
|
</>
|
|
487
504
|
)}
|
|
488
505
|
</div>
|
|
489
|
-
</div
|
|
490
|
-
)
|
|
491
|
-
|
|
492
|
-
</div >
|
|
506
|
+
</div>
|
|
507
|
+
)}
|
|
508
|
+
</div>
|
|
493
509
|
)
|
|
494
510
|
}
|
|
495
511
|
|