@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.
@@ -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 CoveMediaControls from '@cdc/core/components/CoveMediaControls'
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
- <section className='dashboard-filters-section' key={`${singleFilter.key}-filtersection-${index}`}>
457
- <label htmlFor={`filter-${index}`}>{singleFilter.key}</label>
458
- <select
459
- id={`filter-${index}`}
460
- className='filter-select'
461
- data-index='0'
462
- value={singleFilter.active}
463
- onChange={val => {
464
- changeFilterActive(index, val.target.value)
465
- announceChange(`Filter ${singleFilter.key} value has been changed to ${val.target.value}, please reference the data table to see updated values.`)
466
- }}
467
- >
468
- {values}
469
- </select>
470
- </section>
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
- <div className='cove-dashboard-filters'>
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 && <CoveMediaControls.Button title='Download Dashboard as Image' type='image' state={config} text='Download Dashboard Image' elementToCapture={imageId} />}
750
- {config.table.downloadPdfButton && <CoveMediaControls.Button title='Download Dashboard as PDF' type='pdf' state={config} text='Download Dashboard PDF' elementToCapture={imageId} />}
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 CoveMediaControls from '@cdc/core/components/CoveMediaControls'
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
- <CoveMediaControls.Section classes={['download-links']}>
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
- </CoveMediaControls.Section>
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 = (valueIndex) => {
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 = (e) => {
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
- <span className='edit-label column-heading'>Filter Type:</span>
220
- <select defaultValue={filter.type || 'data'} onChange={e => updateFilterProp('type', index, e.target.value)}>
221
- <option value="url">URL</option>
222
- <option value="data">Data</option>
223
- </select>
224
- </label>
225
- {filter.type === 'url' && <>
226
- <label>
227
- <span className='edit-label column-heading'>Label: </span>
228
- <input
229
- type='text'
230
- value={filter.key}
231
- onChange={e => {
232
- updateFilterProp('key', index, e.target.value)
233
- }}
234
- />
235
- </label>
236
- <label>
237
- <span className='edit-label column-heading'>URL to Filter: </span>
238
- <select defaultValue={filter.datasetKey || ''} onChange={e => updateFilterProp('datasetKey', index, e.target.value)}>
239
- <option value=''>- Select Option -</option>
240
- {Object.keys(config.datasets).map(datasetKey => {
241
- if(config.datasets[datasetKey].dataUrl){
242
- return <option key={datasetKey} value={datasetKey}>{(config.datasets[datasetKey].dataUrl).substring(0, 50)}</option>
243
- }
244
- return <React.Fragment key={datasetKey}></React.Fragment>;
245
- })}
246
- </select>
247
- </label>
248
- <label>
249
- <span className='edit-label column-heading'>Query string parameter</span>{' '}
250
- <input
251
- type='text'
252
- defaultValue={filter.queryParameter}
253
- onChange={e => updateFilterProp('queryParameter', index, e.target.value)}
254
- />
255
- </label>
256
- <span className='edit-label column-heading'>Values</span>{' '}
257
- <ul className='value-list'>
258
- {filter.values &&
259
- filter.values.map((value, valueIndex) => (
260
- <li>
261
- {value}
262
- <input
263
- type='text'
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
- <select onChange={e => addFilterUsedBy(filter, index, e.target.value)}>
348
- <option value=''>- Select Option -</option>
349
- {Object.keys(config.visualizations)
350
- .filter(vizKey => filter.setBy !== vizKey && (!filter.usedBy || filter.usedBy.indexOf(vizKey) === -1) && !config.visualizations[vizKey].usesSharedFilter)
351
- .map(vizKey => (
352
- <option value={vizKey} key={`used-by-select-item-${vizKey}`}>
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
- </select>
357
- </label>
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="toggle-bar__wrapper">
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><br />
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><br />
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="wrap">
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="wrap">
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