@cdc/dashboard 4.22.10 → 4.23.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.
@@ -25,25 +25,27 @@ import CdcChart from '@cdc/chart'
25
25
  import CdcDataBite from '@cdc/data-bite'
26
26
  import CdcWaffleChart from '@cdc/waffle-chart'
27
27
  import CdcMarkupInclude from '@cdc/markup-include'
28
- import CdcFilteredText from '@cdc/filtered-text';
28
+ import CdcFilteredText from '@cdc/filtered-text'
29
29
 
30
30
  import Grid from './components/Grid'
31
31
  import Header from './components/Header'
32
32
  import defaults from './data/initial-state'
33
33
  import Widget from './components/Widget'
34
34
  import DataTable from './components/DataTable'
35
+ import CoveMediaControls from '@cdc/core/helpers/CoveMediaControls'
36
+
35
37
 
36
38
  import './scss/main.scss'
37
39
  import '@cdc/core/styles/v2/main.scss'
38
40
 
39
41
  const addVisualization = (type, subType) => {
40
- let modalWillOpen = type === "markup-include" ? false : true;
42
+ let modalWillOpen = type === 'markup-include' ? false : true
41
43
  let newVisualizationConfig = {
42
44
  newViz: true,
43
45
  openModal: modalWillOpen,
44
46
  uid: type + Date.now(),
45
- type,
46
- };
47
+ type
48
+ }
47
49
 
48
50
  switch (type) {
49
51
  case 'chart':
@@ -74,44 +76,45 @@ const addVisualization = (type, subType) => {
74
76
  }
75
77
 
76
78
  const VisualizationsPanel = () => (
77
- <div className="visualizations-panel">
79
+ <div className='visualizations-panel'>
78
80
  <p style={{ fontSize: '14px' }}>Click and drag an item onto the grid to add it to your dashboard.</p>
79
- <span className="subheading-3">Chart</span>
80
- <div className="drag-grid">
81
- <Widget addVisualization={() => addVisualization('chart', 'Bar')} type="Bar"/>
82
- <Widget addVisualization={() => addVisualization('chart', 'Line')} type="Line"/>
83
- <Widget addVisualization={() => addVisualization('chart', 'Pie')} type="Pie"/>
81
+ <span className='subheading-3'>Chart</span>
82
+ <div className='drag-grid'>
83
+ <Widget addVisualization={() => addVisualization('chart', 'Bar')} type='Bar' />
84
+ <Widget addVisualization={() => addVisualization('chart', 'Line')} type='Line' />
85
+ <Widget addVisualization={() => addVisualization('chart', 'Pie')} type='Pie' />
84
86
  </div>
85
- <span className="subheading-3">Map</span>
86
- <div className="drag-grid">
87
- <Widget addVisualization={() => addVisualization('map', 'us')} type="us"/>
88
- <Widget addVisualization={() => addVisualization('map', 'world')} type="world"/>
89
- <Widget addVisualization={() => addVisualization('map', 'single-state')} type="single-state"/>
87
+ <span className='subheading-3'>Map</span>
88
+ <div className='drag-grid'>
89
+ <Widget addVisualization={() => addVisualization('map', 'us')} type='us' />
90
+ <Widget addVisualization={() => addVisualization('map', 'world')} type='world' />
91
+ <Widget addVisualization={() => addVisualization('map', 'single-state')} type='single-state' />
90
92
  </div>
91
- <span className="subheading-3">Misc.</span>
92
- <div className="drag-grid">
93
- <Widget addVisualization={() => addVisualization('data-bite', '')} type="data-bite"/>
94
- <Widget addVisualization={() => addVisualization('waffle-chart', '')} type="waffle-chart"/>
95
- <Widget addVisualization={() => addVisualization('markup-include', '')} type="markup-include"/>
96
- <Widget addVisualization={() => addVisualization('filtered-text', '')} type="filtered-text"/>
93
+ <span className='subheading-3'>Misc.</span>
94
+ <div className='drag-grid'>
95
+ <Widget addVisualization={() => addVisualization('data-bite', '')} type='data-bite' />
96
+ <Widget addVisualization={() => addVisualization('waffle-chart', '')} type='waffle-chart' />
97
+ <Widget addVisualization={() => addVisualization('markup-include', '')} type='markup-include' />
98
+ <Widget addVisualization={() => addVisualization('filtered-text', '')} type='filtered-text' />
97
99
  </div>
98
100
  </div>
99
101
  )
100
102
 
101
103
  export default function CdcDashboard({ configUrl = '', config: configObj = undefined, isEditor = false, setConfig: setParentConfig }) {
102
- const [ config, setConfig ] = useState(configObj ?? {})
103
- const [ data, setData ] = useState([])
104
- const [ filteredData, setFilteredData ] = useState()
105
- const [ loading, setLoading ] = useState(true)
106
- const [ preview, setPreview ] = useState(false)
107
- const [ tabSelected, setTabSelected ] = useState(0);
108
- const [ currentViewport, setCurrentViewport ] = useState('lg')
104
+ const [config, setConfig] = useState(configObj ?? {})
105
+ const [data, setData] = useState([])
106
+ const [filteredData, setFilteredData] = useState()
107
+ const [loading, setLoading] = useState(true)
108
+ const [preview, setPreview] = useState(false)
109
+ const [tabSelected, setTabSelected] = useState(0)
110
+ const [currentViewport, setCurrentViewport] = useState('lg')
111
+ const [imageId, setImageId] = useState(`cove-${Math.random().toString(16).slice(-4)}`)
109
112
 
110
113
  const { title, description } = config.dashboard || config
111
114
 
112
115
  const transform = new DataTransform()
113
116
 
114
- const processData = async (config) => {
117
+ const processData = async config => {
115
118
  let dataset = config.formattedData || config.data
116
119
 
117
120
  if (config.dataUrl) {
@@ -131,44 +134,46 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
131
134
  }
132
135
 
133
136
  const loadConfig = async () => {
134
- let response = configObj || await (await fetch(configUrl)).json()
137
+ let response = configObj || (await (await fetch(configUrl)).json())
135
138
  let newConfig = { ...defaults, ...response }
136
139
  let datasets = {}
137
140
 
138
141
  if (response.datasets) {
139
- await Promise.all(Object.keys(response.datasets).map(async (key) => {
140
- datasets[key] = await processData(response.datasets[key])
141
- }))
142
+ await Promise.all(
143
+ Object.keys(response.datasets).map(async key => {
144
+ datasets[key] = await processData(response.datasets[key])
145
+ })
146
+ )
142
147
  } else {
143
148
  let dataKey = newConfig.dataFileName || 'backwards-compatibility'
144
149
  datasets[dataKey] = await processData(response)
145
150
 
146
- let datasetsFull = {};
151
+ let datasetsFull = {}
147
152
  datasetsFull[dataKey] = {
148
153
  data: datasets[dataKey],
149
154
  dataDescription: newConfig.dataDescription
150
155
  }
151
- newConfig.datasets = datasetsFull;
152
-
156
+ newConfig.datasets = datasetsFull
157
+
153
158
  Object.keys(newConfig.visualizations).forEach(vizKey => {
154
159
  newConfig.visualizations[vizKey].dataKey = dataKey
155
160
  newConfig.visualizations[vizKey].dataDescription = newConfig.dataDescription
156
161
  newConfig.visualizations[vizKey].formattedData = newConfig.formattedData
157
162
  })
158
-
163
+
159
164
  delete newConfig.data
160
165
  delete newConfig.dataUrl
161
166
  delete newConfig.dataFileName
162
167
  delete newConfig.dataFileSourceType
163
168
  delete newConfig.dataDescription
164
169
  delete newConfig.formattedData
165
-
170
+
166
171
  if (newConfig.dashboard && newConfig.dashboard.filters) {
167
172
  newConfig.dashboard.sharedFilters = newConfig.dashboard.sharedFilters || []
168
173
  newConfig.dashboard.filters.forEach(filter => {
169
174
  newConfig.dashboard.sharedFilters.push({ ...filter, key: filter.label, showDropdown: true, usedBy: Object.keys(newConfig.visualizations) })
170
175
  })
171
-
176
+
172
177
  delete newConfig.dashboard.filters
173
178
  }
174
179
  }
@@ -182,11 +187,11 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
182
187
  const filterData = (filters, data) => {
183
188
  let filteredData = []
184
189
 
185
- if(data){
186
- data.forEach((row) => {
190
+ if (data) {
191
+ data.forEach(row => {
187
192
  let add = true
188
193
 
189
- filters.forEach((filter) => {
194
+ filters.forEach(filter => {
190
195
  if (row[filter.columnName] !== filter.active) {
191
196
  add = false
192
197
  }
@@ -211,11 +216,11 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
211
216
  }
212
217
 
213
218
  Object.keys(newConfig.visualizations).forEach(visualizationKey => {
214
- let applicableFilters = newConfig.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.usedBy && sharedFilter.usedBy.indexOf(visualizationKey) !== -1);
215
-
219
+ let applicableFilters = newConfig.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.usedBy && sharedFilter.usedBy.indexOf(visualizationKey) !== -1)
220
+
216
221
  if (applicableFilters.length > 0) {
217
222
  const visualization = newConfig.visualizations[visualizationKey]
218
-
223
+
219
224
  newFilteredData[visualizationKey] = filterData(applicableFilters, visualization.formattedData || data[visualization.dataKey])
220
225
  }
221
226
  })
@@ -229,7 +234,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
229
234
  const values = []
230
235
 
231
236
  Object.keys(data).forEach(key => {
232
- data[key].forEach((row) => {
237
+ data[key].forEach(row => {
233
238
  const value = row[columnName]
234
239
  if (value && false === values.includes(value)) {
235
240
  values.push(value)
@@ -248,7 +253,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
248
253
  newConfig.dashboard.sharedFilters.forEach((filter, i) => {
249
254
  for (let j = 0; j < visualizationKeys.length; j++) {
250
255
  if (visualizationKeys[j] === filter.setBy) {
251
- const filterValues = generateValuesForFilter(filter.columnName, (dataOverride || data))
256
+ const filterValues = generateValuesForFilter(filter.columnName, dataOverride || data)
252
257
 
253
258
  if (newConfig.dashboard.sharedFilters[i].order === 'asc') {
254
259
  filterValues.sort()
@@ -258,23 +263,23 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
258
263
  }
259
264
 
260
265
  newConfig.dashboard.sharedFilters[i].values = filterValues
261
- if(filterValues.length > 0){
262
- newConfig.dashboard.sharedFilters[i].active = newConfig.dashboard.sharedFilters[i].active || newConfig.dashboard.sharedFilters[i].values[0];
266
+ if (filterValues.length > 0) {
267
+ newConfig.dashboard.sharedFilters[i].active = newConfig.dashboard.sharedFilters[i].active || newConfig.dashboard.sharedFilters[i].values[0]
263
268
  }
264
269
  break
265
270
  }
266
271
  }
267
272
 
268
273
  if ((!newConfig.dashboard.sharedFilters[i].values || newConfig.dashboard.sharedFilters[i].values.length === 0) && newConfig.dashboard.sharedFilters[i].showDropdown) {
269
- newConfig.dashboard.sharedFilters[i].values = generateValuesForFilter(filter.columnName, (dataOverride || data))
270
- if(newConfig.dashboard.sharedFilters[i].values.length > 0){
271
- newConfig.dashboard.sharedFilters[i].active = newConfig.dashboard.sharedFilters[i].active || newConfig.dashboard.sharedFilters[i].values[0];
274
+ newConfig.dashboard.sharedFilters[i].values = generateValuesForFilter(filter.columnName, dataOverride || data)
275
+ if (newConfig.dashboard.sharedFilters[i].values.length > 0) {
276
+ newConfig.dashboard.sharedFilters[i].active = newConfig.dashboard.sharedFilters[i].active || newConfig.dashboard.sharedFilters[i].values[0]
272
277
  }
273
278
  }
274
279
  })
275
280
 
276
281
  visualizationKeys.forEach(visualizationKey => {
277
- let applicableFilters = newConfig.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.usedBy && sharedFilter.usedBy.indexOf(visualizationKey) !== -1);
282
+ let applicableFilters = newConfig.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.usedBy && sharedFilter.usedBy.indexOf(visualizationKey) !== -1)
278
283
 
279
284
  if (applicableFilters.length > 0) {
280
285
  newFilteredData[visualizationKey] = filterData(applicableFilters, newConfig.visualizations[visualizationKey].formattedData || newConfig.visualizations[visualizationKey].data || (dataOverride || data)[newConfig.visualizations[visualizationKey].dataKey])
@@ -299,7 +304,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
299
304
  if (setParentConfig && isEditor) {
300
305
  setParentConfig(config)
301
306
  }
302
- }, [ config ])
307
+ }, [config])
303
308
 
304
309
  const updateChildConfig = (visualizationKey, newConfig) => {
305
310
  let updatedConfig = { ...config }
@@ -321,7 +326,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
321
326
  let newFilteredData = {}
322
327
  Object.keys(config.visualizations).forEach(key => {
323
328
  let applicableFilters = dashboardConfig.sharedFilters.filter(sharedFilter => sharedFilter.usedBy && sharedFilter.usedBy.indexOf(key) !== -1)
324
- if(applicableFilters.length > 0){
329
+ if (applicableFilters.length > 0) {
325
330
  newFilteredData[key] = filterData(applicableFilters, config.visualizations[key].formattedData || data[config.visualizations[key].dataKey])
326
331
  }
327
332
  })
@@ -329,7 +334,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
329
334
  setFilteredData(newFilteredData)
330
335
  }
331
336
 
332
- const announceChange = (text) => {}
337
+ const announceChange = text => { }
333
338
 
334
339
  return config.dashboard.sharedFilters.map((singleFilter, index) => {
335
340
  if (!singleFilter.showDropdown) return
@@ -337,22 +342,22 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
337
342
  const values = []
338
343
 
339
344
  singleFilter.values.forEach((filterOption, index) => {
340
- values.push(<option
341
- key={`${singleFilter.key}-option-${index}`}
342
- value={filterOption}
343
- >{filterOption}
344
- </option>)
345
+ values.push(
346
+ <option key={`${singleFilter.key}-option-${index}`} value={filterOption}>
347
+ {filterOption}
348
+ </option>
349
+ )
345
350
  })
346
351
 
347
352
  return (
348
- <section className="dashboard-filters-section" key={`${singleFilter.key}-filtersection-${index}`}>
353
+ <section className='dashboard-filters-section' key={`${singleFilter.key}-filtersection-${index}`}>
349
354
  <label htmlFor={`filter-${index}`}>{singleFilter.key}</label>
350
355
  <select
351
356
  id={`filter-${index}`}
352
- className="filter-select"
353
- data-index="0"
357
+ className='filter-select'
358
+ data-index='0'
354
359
  value={singleFilter.active}
355
- onChange={(val) => {
360
+ onChange={val => {
356
361
  changeFilterActive(index, val.target.value)
357
362
  announceChange(`Filter ${singleFilter.key} value has been changed to ${val.target.value}, please reference the data table to see updated values.`)
358
363
  }}
@@ -379,7 +384,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
379
384
  }, [])
380
385
 
381
386
  // Prevent render if loading
382
- if (loading) return <Loading/>
387
+ if (loading) return <Loading />
383
388
 
384
389
  let body = null
385
390
 
@@ -394,7 +399,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
394
399
 
395
400
  visualizationConfig.data = filteredData && filteredData[visualizationKey] ? filteredData[visualizationKey] : data[dataKey]
396
401
  if (visualizationConfig.formattedData) {
397
- visualizationConfig.originalFormattedData = visualizationConfig.formattedData;
402
+ visualizationConfig.originalFormattedData = visualizationConfig.formattedData
398
403
  visualizationConfig.formattedData = visualizationConfig.data
399
404
  }
400
405
 
@@ -412,82 +417,61 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
412
417
  setConfig(newConfig)
413
418
  }
414
419
 
415
- const updateConfig = (newConfig) => {
416
- let dataCorrectedConfig = visualizationConfig.originalFormattedData ? {...newConfig, formattedData: visualizationConfig.originalFormattedData} : newConfig;
420
+ const updateConfig = newConfig => {
421
+ let dataCorrectedConfig = visualizationConfig.originalFormattedData ? { ...newConfig, formattedData: visualizationConfig.originalFormattedData } : newConfig
417
422
  updateChildConfig(visualizationKey, dataCorrectedConfig)
418
423
  }
419
424
 
420
425
  switch (visualizationConfig.type) {
421
426
  case 'chart':
422
- body = <><Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor="Chart"/>
423
- <CdcChart
424
- key={visualizationKey}
425
- config={visualizationConfig}
426
- isEditor={true}
427
- setConfig={updateConfig}
428
- setSharedFilter={setsSharedFilter ? setSharedFilter : undefined}
429
- isDashboard={true}
430
- />
431
- </>
427
+ body = (
428
+ <>
429
+ <Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor='Chart' />
430
+ <CdcChart key={visualizationKey} config={visualizationConfig} isEditor={true} setConfig={updateConfig} setSharedFilter={setsSharedFilter ? setSharedFilter : undefined} isDashboard={true} />
431
+ </>
432
+ )
432
433
  break
433
434
  case 'map':
434
- body = <><Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor="Map"/>
435
- <CdcMap
436
- key={visualizationKey}
437
- config={visualizationConfig}
438
- isEditor={true}
439
- setConfig={updateConfig}
440
- setSharedFilter={setsSharedFilter ? setSharedFilter : undefined}
441
- setSharedFilterValue={setSharedFilterValue}
442
- isDashboard={true}
443
- />
444
- </>
435
+ body = (
436
+ <>
437
+ <Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor='Map' />
438
+ <CdcMap key={visualizationKey} config={visualizationConfig} isEditor={true} setConfig={updateConfig} setSharedFilter={setsSharedFilter ? setSharedFilter : undefined} setSharedFilterValue={setSharedFilterValue} isDashboard={true} />
439
+ </>
440
+ )
445
441
  break
446
442
  case 'data-bite':
447
443
  visualizationConfig = { ...visualizationConfig, newViz: true }
448
- body = <><Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor="Data Bite"/>
449
- <CdcDataBite
450
- key={visualizationKey}
451
- config={visualizationConfig}
452
- isEditor={true}
453
- setConfig={updateConfig}
454
- isDashboard={true}
455
- />
456
- </>
444
+ body = (
445
+ <>
446
+ <Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor='Data Bite' />
447
+ <CdcDataBite key={visualizationKey} config={visualizationConfig} isEditor={true} setConfig={updateConfig} isDashboard={true} />
448
+ </>
449
+ )
457
450
  break
458
451
  case 'waffle-chart':
459
- body = <><Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor="Waffle Chart"/>
460
- <CdcWaffleChart
461
- key={visualizationKey}
462
- config={visualizationConfig}
463
- isEditor={true}
464
- setConfig={updateConfig}
465
- isDashboard={true}
466
- />
467
- </>
452
+ body = (
453
+ <>
454
+ <Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor='Waffle Chart' />
455
+ <CdcWaffleChart key={visualizationKey} config={visualizationConfig} isEditor={true} setConfig={updateConfig} isDashboard={true} />
456
+ </>
457
+ )
468
458
  break
469
459
  case 'markup-include':
470
- body = <><Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor="Markup Include"/>
471
- <CdcMarkupInclude
472
- key={visualizationKey}
473
- config={visualizationConfig}
474
- isEditor={true}
475
- setConfig={updateConfig}
476
- isDashboard={true}
477
- />
478
- </>
460
+ body = (
461
+ <>
462
+ <Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor='Markup Include' />
463
+ <CdcMarkupInclude key={visualizationKey} config={visualizationConfig} isEditor={true} setConfig={updateConfig} isDashboard={true} />
464
+ </>
465
+ )
479
466
  break
480
- case 'filtered-text':
481
- body = <><Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor="Filtered Text"/>
482
- <CdcFilteredText
483
- key={visualizationKey}
484
- config={visualizationConfig}
485
- isEditor={true}
486
- setConfig={updateConfig}
487
- isDashboard={true}
488
- />
467
+ case 'filtered-text':
468
+ body = (
469
+ <>
470
+ <Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor='Filtered Text' />
471
+ <CdcFilteredText key={visualizationKey} config={visualizationConfig} isEditor={true} setConfig={updateConfig} isDashboard={true} />
489
472
  </>
490
- break
473
+ )
474
+ break
491
475
  default:
492
476
  body = <></>
493
477
  break
@@ -498,10 +482,10 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
498
482
  if (!subVisualizationEditing) {
499
483
  body = (
500
484
  <DndProvider backend={HTML5Backend}>
501
- <Header tabSelected={tabSelected} setTabSelected={setTabSelected} preview={preview} setPreview={setPreview}/>
502
- <div className="layout-container">
503
- <VisualizationsPanel/>
504
- <Grid/>
485
+ <Header tabSelected={tabSelected} setTabSelected={setTabSelected} preview={preview} setPreview={setPreview} />
486
+ <div className='layout-container'>
487
+ <VisualizationsPanel />
488
+ <Grid />
505
489
  </div>
506
490
  </DndProvider>
507
491
  )
@@ -509,164 +493,185 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
509
493
  } else {
510
494
  body = (
511
495
  <>
512
-
513
- {isEditor && <Header tabSelected={tabSelected} setTabSelected={setTabSelected} preview={preview} setPreview={setPreview}/>}
496
+ {isEditor && <Header tabSelected={tabSelected} setTabSelected={setTabSelected} preview={preview} setPreview={setPreview} />}
514
497
  <div className={`cdc-dashboard-inner-container${isEditor ? ' is-editor' : ''}`}>
515
498
  {/* Title */}
516
- {title &&
517
- <div role="heading" aria-level="3" className={`dashboard-title ${config.dashboard.theme ?? 'theme-blue'}`}>{title}</div>}
499
+ {title && (
500
+ <div role='heading' aria-level='3' className={`dashboard-title ${config.dashboard.theme ?? 'theme-blue'}`}>
501
+ {title}
502
+ </div>
503
+ )}
518
504
  {/* Description */}
519
- {description && <div className="subtext">{parse(description)}</div>}
505
+ {description && <div className='subtext'>{parse(description)}</div>}
520
506
  {/* Filters */}
521
- {config.dashboard.sharedFilters && <div className="cove-dashboard-filters"> <Filters/></div>}
507
+ {config.dashboard.sharedFilters && (
508
+ <div className='cove-dashboard-filters'>
509
+ {' '}
510
+ <Filters />
511
+ </div>
512
+ )}
522
513
 
523
514
  {/* Visualizations */}
524
- {config.rows && config.rows.filter(row => row.filter(col => col.widget).length !== 0).map((row, index) => {
515
+ {config.rows &&
516
+ config.rows
517
+ .filter(row => row.filter(col => col.widget).length !== 0)
518
+ .map((row, index) => {
519
+ return (
520
+ <div className={`dashboard-row ${row.equalHeight ? 'equal-height' : ''}`} key={`row__${index}`}>
521
+ {row.map((col, colIndex) => {
522
+ if (col.width) {
523
+ if (!col.widget) return <div key={`row__${index}__col__${colIndex}`} className={`dashboard-col dashboard-col-${col.width}`}></div>
524
+
525
+ let visualizationConfig = { ...config.visualizations[col.widget] }
526
+
527
+ const dataKey = visualizationConfig.dataKey || 'backwards-compatibility'
528
+
529
+ visualizationConfig.data = filteredData && filteredData[col.widget] ? filteredData[col.widget] : data[dataKey]
530
+ if (visualizationConfig.formattedData) {
531
+ visualizationConfig.formattedData = visualizationConfig.data
532
+ }
533
+
534
+ const setsSharedFilter = config.dashboard.sharedFilters && config.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.setBy === col.widget).length > 0
535
+ const setSharedFilterValue = setsSharedFilter ? config.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.setBy === col.widget)[0].active : undefined
536
+ const tableLink = <a href={`#data-table-${visualizationConfig.dataKey}`}>{visualizationConfig.dataKey} (Go to Table)</a>
537
+
538
+ return (
539
+ <React.Fragment key={`vis__${index}__${colIndex}`}>
540
+ <div className={`dashboard-col dashboard-col-${col.width}`}>
541
+ {visualizationConfig.type === 'chart' && (
542
+ <CdcChart
543
+ key={col.widget}
544
+ config={visualizationConfig}
545
+ isEditor={false}
546
+ setConfig={newConfig => {
547
+ updateChildConfig(col.widget, newConfig)
548
+ }}
549
+ setSharedFilter={setsSharedFilter ? setSharedFilter : undefined}
550
+ isDashboard={true}
551
+ link={config.table && config.table.show && config.datasets ? tableLink : undefined}
552
+ />
553
+ )}
554
+ {visualizationConfig.type === 'map' && (
555
+ <CdcMap
556
+ key={col.widget}
557
+ config={visualizationConfig}
558
+ isEditor={false}
559
+ setConfig={newConfig => {
560
+ updateChildConfig(col.widget, newConfig)
561
+ }}
562
+ setSharedFilter={setsSharedFilter ? setSharedFilter : undefined}
563
+ setSharedFilterValue={setSharedFilterValue}
564
+ isDashboard={true}
565
+ link={config.table && config.table.show && config.datasets ? tableLink : undefined}
566
+ />
567
+ )}
568
+ {visualizationConfig.type === 'data-bite' && (
569
+ <CdcDataBite
570
+ key={col.widget}
571
+ config={visualizationConfig}
572
+ isEditor={false}
573
+ setConfig={newConfig => {
574
+ updateChildConfig(col.widget, newConfig)
575
+ }}
576
+ isDashboard={true}
577
+ />
578
+ )}
579
+ {visualizationConfig.type === 'waffle-chart' && (
580
+ <CdcWaffleChart
581
+ key={col.widget}
582
+ config={visualizationConfig}
583
+ isEditor={false}
584
+ setConfig={newConfig => {
585
+ updateChildConfig(col.widget, newConfig)
586
+ }}
587
+ isDashboard={true}
588
+ link={config.table && config.table.show && config.datasets ? tableLink : undefined}
589
+ />
590
+ )}
591
+ {visualizationConfig.type === 'markup-include' && (
592
+ <CdcMarkupInclude
593
+ key={col.widget}
594
+ config={visualizationConfig}
595
+ isEditor={false}
596
+ setConfig={newConfig => {
597
+ updateChildConfig(col.widget, newConfig)
598
+ }}
599
+ isDashboard={true}
600
+ />
601
+ )}
602
+ {visualizationConfig.type === 'filtered-text' && (
603
+ <CdcFilteredText
604
+ key={col.widget}
605
+ config={visualizationConfig}
606
+ isEditor={false}
607
+ setConfig={newConfig => {
608
+ updateChildConfig(col.widget, newConfig)
609
+ }}
610
+ isDashboard={true}
611
+ />
612
+ )}
613
+ </div>
614
+ </React.Fragment>
615
+ )
616
+ }
617
+ return <React.Fragment key={`vis__${index}__${colIndex}`}></React.Fragment>
618
+ })}
619
+ </div>
620
+ )
621
+ })}
622
+
623
+ {/* Image or PDF Inserts */}
624
+ <section className='download-buttons'>
625
+ {config.table.downloadImageButton && <CoveMediaControls.Button title='Download Dashboard as Image' type='image' state={config} text='Download Dashboard Image' elementToCapture={imageId} />}
626
+ {config.table.downloadPdfButton && <CoveMediaControls.Button title='Download Dashboard as PDF' type='pdf' state={config} text='Download Dashboard PDF' elementToCapture={imageId} />}
627
+ </section>
525
628
 
526
- return (
527
-
528
- <div className={`dashboard-row ${row.equalHeight ? 'equal-height' : ''}`} key={`row__${index}`}>
529
- {row.map((col, colIndex) => {
530
- if (col.width) {
531
- if (!col.widget) return <div key={`row__${index}__col__${colIndex}`} className={`dashboard-col dashboard-col-${col.width}`}></div>
532
-
533
- let visualizationConfig = { ...config.visualizations[col.widget] }
534
-
535
- const dataKey = visualizationConfig.dataKey || 'backwards-compatibility'
536
-
537
- visualizationConfig.data = filteredData && filteredData[col.widget] ? filteredData[col.widget] : data[dataKey]
538
- if (visualizationConfig.formattedData) {
539
- visualizationConfig.formattedData = visualizationConfig.data
629
+ {/* Data Table */}
630
+ {config.table && config.data && <DataTable data={config.data} config={config} imageRef={imageId} />}
631
+ {config.table &&
632
+ config.datasets &&
633
+ Object.keys(config.datasets).map(datasetKey => {
634
+ //For each dataset, find any shared filters that apply to all visualizations using the dataset
635
+ //Apply these filters to the table
636
+ let filteredTableData
637
+ if (config.dashboard.sharedFilters && config.dashboard.sharedFilters.length > 0) {
638
+ //Gets list of visuailzations using the dataset
639
+ let vizKeysUsingDataset = []
640
+ Object.keys(config.visualizations).forEach(visualizationKey => {
641
+ if (config.visualizations[visualizationKey].dataKey === datasetKey) {
642
+ vizKeysUsingDataset.push(visualizationKey)
643
+ }
644
+ })
645
+
646
+ //Checks shared filters against list to see if all visualizations are represented
647
+ let applicableFilters = []
648
+ config.dashboard.sharedFilters.forEach(sharedFilter => {
649
+ let allMatch = true
650
+ vizKeysUsingDataset.forEach(visualizationKey => {
651
+ if (sharedFilter.usedBy.indexOf(visualizationKey) === -1) {
652
+ allMatch = false
540
653
  }
541
-
542
- const setsSharedFilter = config.dashboard.sharedFilters && config.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.setBy === col.widget).length > 0
543
- const setSharedFilterValue = setsSharedFilter ? config.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.setBy === col.widget)[0].active : undefined
544
- const tableLink = <a href={`#data-table-${visualizationConfig.dataKey}`}>{visualizationConfig.dataKey} (Go to Table)</a>;
545
-
546
- return (
547
- <React.Fragment key={`vis__${index}__${colIndex}`}>
548
- <div className={`dashboard-col dashboard-col-${col.width}`}>
549
- {visualizationConfig.type === 'chart' && (
550
- <CdcChart
551
- key={col.widget}
552
- config={visualizationConfig}
553
- isEditor={false}
554
- setConfig={(newConfig) => {
555
- updateChildConfig(col.widget, newConfig)
556
- }}
557
- setSharedFilter={setsSharedFilter ? setSharedFilter : undefined}
558
- isDashboard={true}
559
- link = { config.table && config.table.show && config.datasets ? tableLink : undefined }
560
- />
561
- )}
562
- {visualizationConfig.type === 'map' && (
563
- <CdcMap
564
- key={col.widget}
565
- config={visualizationConfig}
566
- isEditor={false}
567
- setConfig={(newConfig) => {
568
- updateChildConfig(col.widget, newConfig)
569
- }}
570
- setSharedFilter={setsSharedFilter ? setSharedFilter : undefined}
571
- setSharedFilterValue={setSharedFilterValue}
572
- isDashboard={true}
573
- link = { config.table && config.table.show && config.datasets ? tableLink : undefined }
574
- />
575
- )}
576
- {visualizationConfig.type === 'data-bite' && (
577
- <CdcDataBite
578
- key={col.widget}
579
- config={visualizationConfig}
580
- isEditor={false}
581
- setConfig={(newConfig) => {
582
- updateChildConfig(col.widget, newConfig)
583
- }}
584
- isDashboard={true}
585
- />
586
- )}
587
- {visualizationConfig.type === 'waffle-chart' && (
588
- <CdcWaffleChart
589
- key={col.widget}
590
- config={visualizationConfig}
591
- isEditor={false}
592
- setConfig={(newConfig) => {
593
- updateChildConfig(col.widget, newConfig)
594
- }}
595
- isDashboard={true}
596
- link = { config.table && config.table.show && config.datasets ? tableLink : undefined }
597
- />
598
- )}
599
- {visualizationConfig.type === 'markup-include' && (
600
- <CdcMarkupInclude
601
- key={col.widget}
602
- config={visualizationConfig}
603
- isEditor={false}
604
- setConfig={(newConfig) => {
605
- updateChildConfig(col.widget, newConfig)
606
- }}
607
- isDashboard={true}
608
- />
609
- )}
610
- {visualizationConfig.type === 'filtered-text' && (
611
- <CdcFilteredText
612
- key={col.widget}
613
- config={visualizationConfig}
614
- isEditor={false}
615
- setConfig={(newConfig) => {
616
- updateChildConfig(col.widget, newConfig)
617
- }}
618
- isDashboard={true}
619
- />
620
- )}
621
- </div>
622
- </React.Fragment>
623
- )
654
+ })
655
+ if (allMatch) {
656
+ applicableFilters.push(sharedFilter)
624
657
  }
625
- return <React.Fragment key={`vis__${index}__${colIndex}`}></React.Fragment>
626
- })}
627
- </div>)
628
- })}
658
+ })
629
659
 
630
- {/* Data Table */}
631
- {config.table && config.table.show && config.data && <DataTable data={config.data} config={config}/>}
632
- {config.table && config.table.show && config.datasets && Object.keys(config.datasets).map(datasetKey => {
633
-
634
- //For each dataset, find any shared filters that apply to all visualizations using the dataset
635
- //Apply these filters to the table
636
- let filteredTableData;
637
- if(config.dashboard.sharedFilters && config.dashboard.sharedFilters.length > 0){
638
- //Gets list of visuailzations using the dataset
639
- let vizKeysUsingDataset = [];
640
- Object.keys(config.visualizations).forEach(visualizationKey => {
641
- if(config.visualizations[visualizationKey].dataKey === datasetKey){
642
- vizKeysUsingDataset.push(visualizationKey);
660
+ //Applys any applicable filters
661
+ if (applicableFilters.length > 0) {
662
+ filteredTableData = filterData(applicableFilters, config.datasets[datasetKey].data)
643
663
  }
644
- });
645
-
646
- //Checks shared filters against list to see if all visualizations are represented
647
- let applicableFilters = [];
648
- config.dashboard.sharedFilters.forEach(sharedFilter => {
649
- let allMatch = true;
650
- vizKeysUsingDataset.forEach(visualizationKey => {
651
- if(sharedFilter.usedBy.indexOf(visualizationKey) === -1){
652
- allMatch = false;
653
- }
654
- });
655
- if(allMatch){
656
- applicableFilters.push(sharedFilter);
657
- }
658
- });
659
-
660
- //Applys any applicable filters
661
- if(applicableFilters.length > 0){
662
- filteredTableData = filterData(applicableFilters, config.datasets[datasetKey].data)
663
664
  }
664
- }
665
665
 
666
- return (<div className="multi-table-container" id={`data-table-${datasetKey}`} key={`data-table-${datasetKey}`}>
667
- <DataTable data={filteredTableData || config.datasets[datasetKey].data} datasetKey={datasetKey} config={config}></DataTable>
668
- </div>)
669
- })}
666
+
667
+ let dataFileSourceType = config.datasets[datasetKey]?.dataFileSourceType
668
+
669
+ return (
670
+ <div className='multi-table-container' id={`data-table-${datasetKey}`} key={`data-table-${datasetKey}`}>
671
+ <DataTable data={filteredTableData || config.datasets[datasetKey].data} dataFileSourceType={dataFileSourceType} datasetKey={datasetKey} config={config} imageRef={imageId}></DataTable>
672
+ </div>
673
+ )
674
+ })}
670
675
  </div>
671
676
  </>
672
677
  )
@@ -681,16 +686,24 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
681
686
  loading,
682
687
  updateConfig,
683
688
  setParentConfig,
684
- setPreview
689
+ setPreview,
690
+ outerContainerRef
685
691
  }
686
692
 
693
+
694
+ const dashboardContainerClasses = [
695
+ 'cdc-open-viz-module',
696
+ 'type-dashboard',
697
+ `${currentViewport}`
698
+ ]
699
+
687
700
  return (
688
701
  <GlobalContextProvider>
689
702
  <ConfigContext.Provider value={contextValues}>
690
- <div className={`cdc-open-viz-module type-dashboard ${currentViewport}`} ref={outerContainerRef}>
703
+ <div className={dashboardContainerClasses.join(' ')} ref={outerContainerRef} data-download-id={imageId} >
691
704
  {body}
692
705
  </div>
693
- <OverlayFrame/>
706
+ <OverlayFrame />
694
707
  </ConfigContext.Provider>
695
708
  </GlobalContextProvider>
696
709
  )