@cdc/dashboard 4.24.3 → 4.24.5

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.
Files changed (37) hide show
  1. package/dist/cdcdashboard.js +148123 -105018
  2. package/examples/chart-data.json +5409 -0
  3. package/examples/full-dash-test.json +14643 -0
  4. package/examples/full-dashboard.json +10036 -0
  5. package/index.html +2 -2
  6. package/package.json +9 -9
  7. package/src/CdcDashboard.tsx +8 -3
  8. package/src/CdcDashboardComponent.tsx +141 -290
  9. package/src/_stories/Dashboard.stories.tsx +52 -7
  10. package/src/_stories/_mock/markup-include.json +78 -0
  11. package/src/_stories/_mock/multi-dashboards.json +914 -0
  12. package/src/_stories/_mock/multi-viz.json +378 -0
  13. package/src/_stories/_mock/pivot-filter.json +2 -2
  14. package/src/_stories/_mock/standalone-table.json +2 -0
  15. package/src/components/DataDesignerModal.tsx +145 -0
  16. package/src/components/Grid.tsx +3 -1
  17. package/src/components/Header/FilterModal.tsx +63 -33
  18. package/src/components/MultiConfigTabs/MultiTabs.tsx +3 -2
  19. package/src/components/Row.tsx +50 -25
  20. package/src/components/Toggle/Toggle.tsx +6 -7
  21. package/src/components/VisualizationRow.tsx +183 -0
  22. package/src/components/VisualizationsPanel.tsx +26 -3
  23. package/src/components/Widget.tsx +21 -103
  24. package/src/helpers/filterData.ts +1 -1
  25. package/src/helpers/getFilteredData.ts +39 -0
  26. package/src/helpers/getUpdateConfig.ts +15 -0
  27. package/src/helpers/getVizConfig.ts +31 -0
  28. package/src/helpers/getVizRowColumnLocator.ts +9 -0
  29. package/src/scss/grid.scss +9 -2
  30. package/src/scss/main.scss +5 -0
  31. package/src/store/dashboard.actions.ts +6 -0
  32. package/src/store/dashboard.reducer.ts +33 -8
  33. package/src/types/ConfigRow.ts +12 -3
  34. package/src/types/DataSet.ts +11 -8
  35. package/src/types/SharedFilter.ts +1 -1
  36. package/src/components/EditorWrapper/EditorWrapper.tsx +0 -52
  37. package/src/components/EditorWrapper/editor-wrapper.style.css +0 -13
package/index.html CHANGED
@@ -21,12 +21,12 @@
21
21
  </head>
22
22
 
23
23
  <body>
24
- <!-- <div class="react-container" data-config="/examples/private/test.json"></div> -->
24
+ <div class="react-container" data-config="/examples/full-dashboard.json"></div>
25
25
  <!-- <div class="react-container" data-config="/examples/dashboard-gallery.json"></div> -->
26
26
  <!-- <div class="react-container" data-config="/examples/filtered-dash.json"></div> -->
27
27
  <!-- <div class="react-container" data-config="/examples/all-components.json"></div> -->
28
28
  <!-- <div class="react-container" data-config="/examples/sankey.json"></div> -->
29
- <div class="react-container" data-config="/examples/DEV-6574.json"></div>
29
+ <!-- <div class="react-container" data-config="/examples/DEV-6574.json"></div> -->
30
30
  <!-- <div class="react-container" data-config="/examples/default-multi-dataset-2.json"></div> -->
31
31
  <!-- <div class="react-container" data-config="/examples/default-multi-dataset.json"></div> -->
32
32
  <!-- <div class="react-container" data-config="/examples/default-filter-control.json"></div> -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdc/dashboard",
3
- "version": "4.24.3",
3
+ "version": "4.24.5",
4
4
  "description": "React component for combining multiple visualizations into a single dashboard",
5
5
  "moduleName": "CdcDashboard",
6
6
  "main": "dist/cdcdashboard",
@@ -26,13 +26,13 @@
26
26
  },
27
27
  "license": "Apache-2.0",
28
28
  "dependencies": {
29
- "@cdc/chart": "^4.24.3",
30
- "@cdc/core": "^4.24.3",
31
- "@cdc/data-bite": "^4.24.3",
32
- "@cdc/filtered-text": "^4.24.3",
33
- "@cdc/map": "^4.24.3",
34
- "@cdc/markup-include": "^4.24.3",
35
- "@cdc/waffle-chart": "^4.24.3",
29
+ "@cdc/chart": "^4.24.5",
30
+ "@cdc/core": "^4.24.5",
31
+ "@cdc/data-bite": "^4.24.5",
32
+ "@cdc/filtered-text": "^4.24.5",
33
+ "@cdc/map": "^4.24.5",
34
+ "@cdc/markup-include": "^4.24.5",
35
+ "@cdc/waffle-chart": "^4.24.5",
36
36
  "html-react-parser": "^3.0.8",
37
37
  "js-base64": "^2.5.2",
38
38
  "papaparse": "^5.3.0",
@@ -48,5 +48,5 @@
48
48
  "react": "^18.2.0",
49
49
  "react-dom": "^18.2.0"
50
50
  },
51
- "gitHead": "9c7ef7ca74f2d2a1e04d923b133fe0fc557a62bf"
51
+ "gitHead": "def85aaf4cd9dc1983e80f2900199f35de82af95"
52
52
  }
@@ -11,6 +11,7 @@ import { initialState } from './DashboardContext'
11
11
  import { getUpdateConfig } from './helpers/getUpdateConfig'
12
12
  import { InitialState } from './types/InitialState'
13
13
  import { DashboardConfig } from './types/DashboardConfig'
14
+ import { coveUpdateWorker } from '@cdc/core/helpers/coveUpdateWorker'
14
15
  import _ from 'lodash'
15
16
 
16
17
  type MultiDashboardProps = Omit<WCMSProps, 'configUrl'> & {
@@ -36,7 +37,8 @@ const MultiDashboardWrapper: React.FC<MultiDashboardProps> = ({ configUrl, confi
36
37
 
37
38
  const formatInitialState = (newConfig: MultiDashboardConfig | DashboardConfig, datasets: Record<string, Object[]>) => {
38
39
  const [config, filteredData] = getUpdateConfig(initialState)(newConfig, datasets)
39
- return { ...initialState, config, filteredData, data: datasets }
40
+ const versionedConfig = coveUpdateWorker(config)
41
+ return { ...initialState, config: versionedConfig, filteredData, data: datasets }
40
42
  }
41
43
 
42
44
  const loadConfig = async (selectedConfig?: string) => {
@@ -62,7 +64,10 @@ const MultiDashboardWrapper: React.FC<MultiDashboardProps> = ({ configUrl, confi
62
64
  )
63
65
 
64
66
  getVizKeys(newConfig).forEach(vizKey => {
65
- newConfig.visualizations[vizKey].formattedData = datasets[newConfig.visualizations[vizKey].dataKey]
67
+ const formattedData = datasets[newConfig.visualizations[vizKey].dataKey]
68
+ if (formattedData) {
69
+ newConfig.visualizations[vizKey].formattedData = formattedData
70
+ }
66
71
  })
67
72
 
68
73
  Object.keys(datasets).forEach(key => {
@@ -92,7 +97,7 @@ const MultiDashboardWrapper: React.FC<MultiDashboardProps> = ({ configUrl, confi
92
97
  newConfig.visualizations[vizKey] = { ...newConfig.visualizations[vizKey], ...newData }
93
98
  })
94
99
 
95
- const blankFields = { data: [], dataUrl: '', dataFileName: '', dataFileSourceType: '', dataDescription: [], formattedData: [] }
100
+ const blankFields = { data: [], dataUrl: '', dataFileName: '', dataFileSourceType: '', dataDescription: {}, formattedData: [] }
96
101
  newConfig = { ...newConfig, ...blankFields }
97
102
 
98
103
  if (newConfig.dashboard.filters) {
@@ -40,7 +40,6 @@ import { capitalizeSplitAndJoin } from '@cdc/core/helpers/cove/string'
40
40
  import VisualizationsPanel from './components/VisualizationsPanel'
41
41
  import dashboardReducer from './store/dashboard.reducer'
42
42
  import { filterData } from './helpers/filterData'
43
- import { getFormattedData } from './helpers/getFormattedData'
44
43
  import { getVizKeys } from './helpers/getVizKeys'
45
44
  import Title from '@cdc/core/components/ui/Title'
46
45
  import { type TableConfig } from '@cdc/core/components/DataTable/types/TableConfig'
@@ -56,12 +55,13 @@ import _ from 'lodash'
56
55
  import EditorContext from '../../editor/src/ConfigContext'
57
56
  import { getApiFilterKey } from './helpers/getApiFilterKey'
58
57
  import Filters, { APIFilterDropdowns, DropdownOptions } from './components/Filters'
59
- import EditorWrapper from './components/EditorWrapper/EditorWrapper'
60
- import DataTableEditorPanel from '@cdc/core/components/DataTable/components/DataTableEditorPanel'
61
58
  import DataTableStandAlone from '@cdc/core/components/DataTable/DataTableStandAlone'
62
59
  import { ViewPort } from '@cdc/core/types/ViewPort'
63
- import Toggle from './components/Toggle'
64
- import { Dashboard } from './types/Dashboard'
60
+ import VisualizationRow from './components/VisualizationRow'
61
+ import { getVizConfig } from './helpers/getVizConfig'
62
+ import { getFilteredData } from './helpers/getFilteredData'
63
+ import { getVizRowColumnLocator } from './helpers/getVizRowColumnLocator'
64
+ import Layout from '@cdc/core/components/Layout'
65
65
 
66
66
  type DashboardProps = Omit<WCMSProps, 'configUrl'> & {
67
67
  initialState: InitialState
@@ -87,6 +87,8 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
87
87
  return vals.some(val => val === undefined)
88
88
  }, [state.data])
89
89
 
90
+ const vizRowColumnLocator = getVizRowColumnLocator(state.config.rows)
91
+
90
92
  const getAutoLoadVisualization = (): Visualization | undefined => {
91
93
  const autoLoadViz = Object.values(state.config.visualizations).filter(vis => {
92
94
  return vis.autoLoad && vis.type === 'filter-dropdowns'
@@ -165,11 +167,6 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
165
167
  }
166
168
  }
167
169
 
168
- const getApplicableFilters = (dashboard: Dashboard, key: string): false | SharedFilter[] => {
169
- const c = dashboard.sharedFilters?.filter(sharedFilter => sharedFilter.usedBy && sharedFilter.usedBy.indexOf(key) !== -1)
170
- return c?.length > 0 ? c : false
171
- }
172
-
173
170
  const reloadURLData = async () => {
174
171
  const { config } = state
175
172
  if (!config.datasets) return
@@ -261,20 +258,15 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
261
258
  if (datasetsNeedsUpdate) {
262
259
  dispatch({ type: 'SET_DATA', payload: newData })
263
260
 
264
- let newFilteredData = {}
265
- let visualizations = { ...config.visualizations }
266
- getVizKeys(config).forEach(key => {
267
- let dataKey = config.visualizations[key].dataKey
268
-
269
- const applicableFilters = getApplicableFilters(config.dashboard, key)
270
- if (applicableFilters) {
271
- newFilteredData[key] = filterData(applicableFilters, newData[dataKey])
272
- }
261
+ const newFilteredData = getFilteredData(state, {}, newData)
273
262
 
263
+ const visualizations = Object.keys(config.visualizations).reduce((acc, vizKey) => {
264
+ const dataKey = config.visualizations[vizKey].dataKey
274
265
  if (newData[dataKey]) {
275
- visualizations[key].formattedData = newData[dataKey]
266
+ acc[vizKey].formattedData = newData[dataKey]
276
267
  }
277
- })
268
+ return acc
269
+ }, _.cloneDeep(config.visualizations))
278
270
 
279
271
  dispatch({ type: 'SET_FILTERED_DATA', payload: newFilteredData })
280
272
  dispatch({ type: 'SET_CONFIG', payload: { ...config, datasets: newDatasets, visualizations } })
@@ -294,7 +286,7 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
294
286
  const setSharedFilter = (key, datum) => {
295
287
  const { config } = state
296
288
  let newConfig = { ...config }
297
- let newFilteredData = { ...state.filteredData }
289
+
298
290
  for (let i = 0; i < newConfig.dashboard.sharedFilters.length; i++) {
299
291
  const filter = newConfig.dashboard.sharedFilters[i]
300
292
  if (filter.setBy === key) {
@@ -305,28 +297,20 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
305
297
  }
306
298
  }
307
299
 
308
- getVizKeys(newConfig).forEach(visualizationKey => {
309
- const applicableFilters = getApplicableFilters(newConfig.dashboard, visualizationKey)
310
- if (applicableFilters) {
311
- const visualization = newConfig.visualizations[visualizationKey]
312
-
313
- const formattedData = visualization.dataDescription ? getFormattedData(state.data[visualization.dataKey] || visualization.data, visualization.dataDescription) : undefined
314
-
315
- newFilteredData[visualizationKey] = filterData(applicableFilters, formattedData || state.data[visualization.dataKey])
316
- }
317
- })
300
+ const newFilteredData = getFilteredData(state, _.cloneDeep(state.filteredData))
318
301
 
319
302
  dispatch({ type: 'SET_FILTERED_DATA', payload: newFilteredData })
320
303
  dispatch({ type: 'SET_CONFIG', payload: newConfig })
321
304
  }
322
305
 
323
306
  useEffect(() => {
307
+ if (state.tabSelected && state.tabSelected !== 'Dashboard Preview') return
324
308
  const { config } = state
325
309
  if (config.filterBehavior !== FilterBehavior.Apply) {
326
310
  reloadURLData()
327
311
  }
328
312
  loadAPIFilters()
329
- }, [JSON.stringify(state.config.dashboard ? state.config.dashboard.sharedFilters : undefined)])
313
+ }, [])
330
314
 
331
315
  const updateChildConfig = (visualizationKey, newConfig) => {
332
316
  const { config } = state
@@ -374,7 +358,7 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
374
358
  }
375
359
 
376
360
  dispatch({ type: 'SET_CONFIG', payload: { ...state.config, dashboard: dashboardConfig } })
377
- updateDataFilters()
361
+ dispatch({ type: 'SET_FILTERED_DATA', payload: getFilteredData(state) })
378
362
  reloadURLData()
379
363
  } else {
380
364
  // TODO noftify of required fields
@@ -401,30 +385,11 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
401
385
 
402
386
  dispatch({ type: 'SET_CONFIG', payload: { ...config, dashboard: dashboardConfig } })
403
387
  if (config.filterBehavior !== FilterBehavior.Apply) {
404
- updateDataFilters()
388
+ dispatch({ type: 'SET_FILTERED_DATA', payload: getFilteredData(state) })
405
389
  reloadURLData()
406
390
  }
407
391
  }
408
392
 
409
- const updateDataFilters = () => {
410
- const { config } = state
411
- const dashboardConfig = { ...config.dashboard }
412
-
413
- const newFilteredData = {}
414
- getVizKeys(config).forEach(key => {
415
- const applicableFilters = getApplicableFilters(dashboardConfig, key)
416
- if (applicableFilters) {
417
- const visualization = config.visualizations[key]
418
- const _data = state.data[visualization.dataKey] || visualization.data
419
- const formattedData = visualization.dataDescription ? getFormattedData(_data, visualization.dataDescription) : _data
420
-
421
- newFilteredData[key] = filterData(applicableFilters, formattedData)
422
- }
423
- })
424
-
425
- dispatch({ type: 'SET_FILTERED_DATA', payload: newFilteredData })
426
- }
427
-
428
393
  const handleOnChange = (index: number, value: string | string[]) => {
429
394
  const { config } = state
430
395
  changeFilterActive(index, value)
@@ -499,23 +464,8 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
499
464
  let subVisualizationEditing = false
500
465
 
501
466
  getVizKeys(state.config).forEach(visualizationKey => {
502
- const visualizationConfig = _.cloneDeep(state.config.visualizations[visualizationKey])
503
-
504
- const dataKey = visualizationConfig.dataKey || 'backwards-compatibility'
505
-
506
- if (state.filteredData && state.filteredData[visualizationKey]) {
507
- visualizationConfig.data = state.filteredData[visualizationKey]
508
- if (visualizationConfig.formattedData) {
509
- visualizationConfig.originalFormattedData = visualizationConfig.formattedData
510
- visualizationConfig.formattedData = visualizationConfig.data
511
- }
512
- } else {
513
- visualizationConfig.data = state.data[dataKey]
514
- if (visualizationConfig.formattedData) {
515
- visualizationConfig.originalFormattedData = visualizationConfig.formattedData
516
- visualizationConfig.formattedData = transform.developerStandardize(visualizationConfig.data, visualizationConfig.dataDescription) || visualizationConfig.data
517
- }
518
- }
467
+ const rowNumber = vizRowColumnLocator[visualizationKey]?.row
468
+ const visualizationConfig = getVizConfig(visualizationKey, rowNumber, state.config, state.data, state.filteredData)
519
469
 
520
470
  const setsSharedFilter = state.config.dashboard.sharedFilters && state.config.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.setBy === visualizationKey).length > 0
521
471
  const setSharedFilterValue = setsSharedFilter ? state.config.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.setBy === visualizationKey)[0].active : undefined
@@ -616,9 +566,10 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
616
566
  break
617
567
  case 'table':
618
568
  body = (
619
- <EditorWrapper component={DataTableStandAlone} visualizationKey={visualizationKey} visualizationConfig={visualizationConfig} updateConfig={_updateConfig} type={'Table'} viewport={currentViewport}>
620
- <DataTableEditorPanel key={visualizationKey} config={visualizationConfig} updateConfig={_updateConfig} />
621
- </EditorWrapper>
569
+ <>
570
+ <Header visualizationKey={visualizationKey} subEditor='Table' />
571
+ <DataTableStandAlone visualizationKey={visualizationKey} config={visualizationConfig} isEditor={true} updateConfig={_updateConfig} />
572
+ </>
622
573
  )
623
574
  break
624
575
  default:
@@ -649,226 +600,126 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
649
600
  <>
650
601
  {isEditor && <Header />}
651
602
  <MultiTabs isEditor={isEditor && !isPreview} />
652
- <div className={`cdc-dashboard-inner-container${isEditor ? ' is-editor' : ''}`}>
653
- <Title title={title} isDashboard={true} classes={[`dashboard-title`, `${config.dashboard.theme ?? 'theme-blue'}`]} />
654
- {/* Description */}
655
- {description && <div className='subtext'>{parse(description)}</div>}
656
-
657
- {/* Filters */}
658
- {config.dashboard.sharedFilters && Object.values(config.visualizations || {}).filter(viz => viz.visualizationType === 'filter-dropdowns').length === 0 && (
659
- <>
660
- <Filters filters={state.config.dashboard.sharedFilters} apiFilterDropdowns={apiFilterDropdowns} handleOnChange={handleOnChange} />
661
- <GoButton />
662
- </>
663
- )}
664
-
665
- {/* Visualizations */}
666
- {config.rows &&
667
- config.rows
668
- .filter(row => row.filter(col => col.widget).length !== 0)
669
- .map((row, index) => {
670
- const isToggleRow = row[0].toggle
603
+ <Layout.Responsive isEditor={isEditor}>
604
+ <div className={`cdc-dashboard-inner-container${isEditor ? ' is-editor' : ''}`}>
605
+ <Title title={title} isDashboard={true} classes={[`dashboard-title`, `${config.dashboard.theme ?? 'theme-blue'}`]} />
606
+ {/* Description */}
607
+ {description && <div className='subtext'>{parse(description)}</div>}
608
+
609
+ {/* Filters */}
610
+ {config.dashboard.sharedFilters && Object.values(config.visualizations || {}).filter(viz => viz.visualizationType === 'filter-dropdowns').length === 0 && (
611
+ <>
612
+ <Filters filters={state.config.dashboard.sharedFilters} apiFilterDropdowns={apiFilterDropdowns} handleOnChange={handleOnChange} />
613
+ <GoButton />
614
+ </>
615
+ )}
616
+
617
+ {/* Visualizations */}
618
+ {config.rows &&
619
+ config.rows
620
+ .filter(row => row.columns.filter(col => col.widget).length !== 0)
621
+ .map((row, index) => {
622
+ if (row.multiVizColumn && (isPreview || !isEditor)) {
623
+ const filteredData = getFilteredData(state)
624
+ const data = filteredData[index] ?? row.formattedData
625
+ const dataGroups = {}
626
+ data.forEach(d => {
627
+ const groupKey = d[row.multiVizColumn]
628
+ if (!dataGroups[groupKey]) dataGroups[groupKey] = []
629
+ dataGroups[groupKey].push(d)
630
+ })
631
+ return Object.keys(dataGroups).map(groupName => {
632
+ const dataValue = dataGroups[groupName]
633
+ return (
634
+ <React.Fragment key={`row__${index}__${groupName}`}>
635
+ <h1 className='h4'>{groupName}</h1>
636
+ <VisualizationRow
637
+ filteredDataOverride={dataValue}
638
+ row={row}
639
+ rowIndex={index}
640
+ setSharedFilter={setSharedFilter}
641
+ updateChildConfig={updateChildConfig}
642
+ applyFilters={applyFilters}
643
+ apiFilterDropdowns={apiFilterDropdowns}
644
+ handleOnChange={handleOnChange}
645
+ currentViewport={currentViewport}
646
+ />
647
+ </React.Fragment>
648
+ )
649
+ })
650
+ } else {
651
+ return (
652
+ <VisualizationRow key={`row__${index}`} row={row} rowIndex={index} setSharedFilter={setSharedFilter} updateChildConfig={updateChildConfig} applyFilters={applyFilters} apiFilterDropdowns={apiFilterDropdowns} handleOnChange={handleOnChange} currentViewport={currentViewport} />
653
+ )
654
+ }
655
+ })}
656
+
657
+ {/* Image or PDF Inserts */}
658
+ <section className='download-buttons'>
659
+ {config.table?.downloadImageButton && <MediaControls.Button title='Download Dashboard as Image' type='image' state={config} text='Download Dashboard Image' elementToCapture={imageId} />}
660
+ {config.table?.downloadPdfButton && <MediaControls.Button title='Download Dashboard as PDF' type='pdf' state={config} text='Download Dashboard PDF' elementToCapture={imageId} />}
661
+ </section>
662
+
663
+ {/* Data Table */}
664
+ {config.table?.show && config.data && (
665
+ <DataTable
666
+ config={config}
667
+ rawData={config.data?.[0]?.tableData ? config.data?.[0]?.tableData : config.data}
668
+ runtimeData={config.data?.[0]?.tableData ? config.data?.[0]?.tableData : config.data || []}
669
+ expandDataTable={config.table.expanded}
670
+ showDownloadButton={config.table.download}
671
+ tableTitle={config.dashboard.title || ''}
672
+ viewport={currentViewport}
673
+ tabbingId={config.dashboard.title || ''}
674
+ outerContainerRef={outerContainerRef}
675
+ imageRef={imageId}
676
+ isDebug={isDebug}
677
+ isEditor={isEditor}
678
+ />
679
+ )}
680
+ {config.table?.show &&
681
+ config.datasets &&
682
+ Object.keys(config.datasets).map(datasetKey => {
683
+ //For each dataset, find any shared filters that apply to all visualizations using the dataset
684
+
685
+ //Gets list of visuailzations using the dataset
686
+ const vizKeysUsingDataset: string[] = getVizKeys(config).filter(visualizationKey => {
687
+ return config.visualizations[visualizationKey].dataKey === datasetKey
688
+ })
689
+
690
+ //Checks shared filters against list to see if all visualizations are represented
691
+ let applicableFilters: SharedFilter[] = []
692
+ config.dashboard.sharedFilters?.forEach(sharedFilter => {
693
+ let allMatch = true
694
+ vizKeysUsingDataset.forEach(visualizationKey => {
695
+ if (sharedFilter.usedBy && sharedFilter.usedBy.indexOf(visualizationKey) === -1) {
696
+ allMatch = false
697
+ }
698
+ })
699
+ if (allMatch) {
700
+ applicableFilters.push(sharedFilter)
701
+ }
702
+ })
703
+
704
+ //Applys any applicable filters to the Table
705
+ const filteredTableData = applicableFilters.length > 0 ? filterData(applicableFilters, config.datasets[datasetKey].data) : undefined
671
706
  return (
672
- <div className={`dashboard-row ${row.equalHeight ? 'equal-height' : ''} ${isToggleRow ? 'toggle' : ''}`} key={`row__${index}`}>
673
- {isToggleRow && <Toggle row={row} rowIndex={index} visualizations={config.visualizations} />}
674
- {row.map((col, colIndex) => {
675
- if (col.width) {
676
- if (!col.widget) return <div key={`row__${index}__col__${colIndex}`} className={`dashboard-col dashboard-col-${col.width}`}></div>
677
-
678
- const visualizationConfig = _.cloneDeep(config.visualizations[col.widget])
679
-
680
- const dataKey = visualizationConfig.dataKey || 'backwards-compatibility'
681
-
682
- if (state.filteredData && state.filteredData[col.widget]) {
683
- visualizationConfig.data = state.filteredData[col.widget]
684
- if (visualizationConfig.formattedData) {
685
- visualizationConfig.originalFormattedData = visualizationConfig.formattedData
686
- visualizationConfig.formattedData = visualizationConfig.data
687
- }
688
- } else {
689
- visualizationConfig.data = state.data[dataKey]
690
- if (visualizationConfig.formattedData) {
691
- visualizationConfig.originalFormattedData = visualizationConfig.formattedData
692
- visualizationConfig.formattedData = transform.developerStandardize(visualizationConfig.data, visualizationConfig.dataDescription) || visualizationConfig.data
693
- }
694
- }
695
-
696
- const setsSharedFilter = config.dashboard.sharedFilters && config.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.setBy === col.widget).length > 0
697
- const setSharedFilterValue = setsSharedFilter ? config.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.setBy === col.widget)[0].active : undefined
698
- const tableLink = (
699
- <a href={`#data-table-${visualizationConfig.dataKey}`} className='margin-left-href'>
700
- {visualizationConfig.dataKey} (Go to Table)
701
- </a>
702
- )
703
- const hideFilter = visualizationConfig.autoLoad && inNoDataState
704
-
705
- const hiddenToggle = col.hide !== undefined ? col.hide : colIndex !== 0
706
- const hidden = col.toggle ? hiddenToggle : false
707
- return (
708
- <React.Fragment key={`vis__${index}__${colIndex}`}>
709
- <div className={`dashboard-col dashboard-col-${col.width} ${hidden ? 'hidden-toggle' : ''}`}>
710
- {visualizationConfig.type === 'chart' && (
711
- <CdcChart
712
- key={col.widget}
713
- config={visualizationConfig}
714
- dashboardConfig={config}
715
- isEditor={false}
716
- setConfig={newConfig => {
717
- updateChildConfig(col.widget, newConfig)
718
- }}
719
- setSharedFilter={setsSharedFilter ? setSharedFilter : undefined}
720
- isDashboard={true}
721
- link={config.table && config.table.show && config.datasets && visualizationConfig.table && visualizationConfig.table.showDataTableLink ? tableLink : undefined}
722
- configUrl={undefined}
723
- setEditing={undefined}
724
- hostname={undefined}
725
- setSharedFilterValue={undefined}
726
- />
727
- )}
728
- {visualizationConfig.type === 'map' && (
729
- <CdcMap
730
- key={col.widget}
731
- config={visualizationConfig}
732
- isEditor={false}
733
- setConfig={newConfig => {
734
- updateChildConfig(col.widget, newConfig)
735
- }}
736
- showLoader={false}
737
- setSharedFilter={setsSharedFilter ? setSharedFilter : undefined}
738
- setSharedFilterValue={setSharedFilterValue}
739
- isDashboard={true}
740
- link={config.table && config.table.show && config.datasets && visualizationConfig.table && visualizationConfig.table.showDataTableLink ? tableLink : undefined}
741
- />
742
- )}
743
- {visualizationConfig.type === 'data-bite' && (
744
- <CdcDataBite
745
- key={col.widget}
746
- config={visualizationConfig}
747
- isEditor={false}
748
- setConfig={newConfig => {
749
- updateChildConfig(col.widget, newConfig)
750
- }}
751
- isDashboard={true}
752
- />
753
- )}
754
- {visualizationConfig.type === 'waffle-chart' && (
755
- <CdcWaffleChart
756
- key={col.widget}
757
- config={visualizationConfig}
758
- isEditor={false}
759
- setConfig={newConfig => {
760
- updateChildConfig(col.widget, newConfig)
761
- }}
762
- isDashboard={true}
763
- configUrl={config.table && config.table.show && config.datasets && visualizationConfig.table && visualizationConfig.table.showDataTableLink ? tableLink : undefined}
764
- />
765
- )}
766
- {visualizationConfig.type === 'markup-include' && (
767
- <CdcMarkupInclude
768
- key={col.widget}
769
- config={visualizationConfig}
770
- isEditor={false}
771
- setConfig={newConfig => {
772
- updateChildConfig(col.widget, newConfig)
773
- }}
774
- isDashboard={true}
775
- configUrl={undefined}
776
- />
777
- )}
778
- {visualizationConfig.type === 'filtered-text' && (
779
- <CdcFilteredText
780
- key={col.widget}
781
- config={visualizationConfig}
782
- isEditor={false}
783
- setConfig={newConfig => {
784
- updateChildConfig(col.widget, newConfig)
785
- }}
786
- isDashboard={true}
787
- configUrl={undefined}
788
- />
789
- )}
790
- {visualizationConfig.type === 'filter-dropdowns' && !hideFilter && (
791
- <>
792
- <Filters hide={visualizationConfig.hide} filters={state.config.dashboard.sharedFilters} apiFilterDropdowns={apiFilterDropdowns} handleOnChange={handleOnChange} />
793
- <GoButton autoLoad={visualizationConfig.autoLoad} />
794
- </>
795
- )}
796
- {visualizationConfig.type === 'table' && <DataTableStandAlone key={col.widget} visualizationKey={col.widget} config={visualizationConfig} viewport={currentViewport} />}
797
- </div>
798
- </React.Fragment>
799
- )
800
- }
801
- return <React.Fragment key={`vis__${index}__${colIndex}`}></React.Fragment>
802
- })}
707
+ <div className='multi-table-container' id={`data-table-${datasetKey}`} key={`data-table-${datasetKey}`}>
708
+ <DataTable
709
+ config={config as TableConfig}
710
+ dataConfig={config.datasets[datasetKey]}
711
+ rawData={config.datasets[datasetKey].data?.[0]?.tableData || config.datasets[datasetKey].data}
712
+ runtimeData={config.datasets[datasetKey].data?.[0]?.tableData || filteredTableData || config.datasets[datasetKey].data || []}
713
+ expandDataTable={config.table.expanded}
714
+ tableTitle={datasetKey}
715
+ viewport={currentViewport}
716
+ tabbingId={datasetKey}
717
+ />
803
718
  </div>
804
719
  )
805
720
  })}
806
-
807
- {/* Image or PDF Inserts */}
808
- <section className='download-buttons'>
809
- {config.table?.downloadImageButton && <MediaControls.Button title='Download Dashboard as Image' type='image' state={config} text='Download Dashboard Image' elementToCapture={imageId} />}
810
- {config.table?.downloadPdfButton && <MediaControls.Button title='Download Dashboard as PDF' type='pdf' state={config} text='Download Dashboard PDF' elementToCapture={imageId} />}
811
- </section>
812
-
813
- {/* Data Table */}
814
- {config.table?.show && config.data && (
815
- <DataTable
816
- config={config}
817
- rawData={config.data?.[0]?.tableData ? config.data?.[0]?.tableData : config.data}
818
- runtimeData={config.data?.[0]?.tableData ? config.data?.[0]?.tableData : config.data || []}
819
- expandDataTable={config.table.expanded}
820
- showDownloadButton={config.table.download}
821
- tableTitle={config.dashboard.title || ''}
822
- viewport={currentViewport}
823
- tabbingId={config.dashboard.title || ''}
824
- outerContainerRef={outerContainerRef}
825
- imageRef={imageId}
826
- isDebug={isDebug}
827
- isEditor={isEditor}
828
- />
829
- )}
830
- {config.table?.show &&
831
- config.datasets &&
832
- Object.keys(config.datasets).map(datasetKey => {
833
- //For each dataset, find any shared filters that apply to all visualizations using the dataset
834
-
835
- //Gets list of visuailzations using the dataset
836
- const vizKeysUsingDataset: string[] = getVizKeys(config).filter(visualizationKey => {
837
- return config.visualizations[visualizationKey].dataKey === datasetKey
838
- })
839
-
840
- //Checks shared filters against list to see if all visualizations are represented
841
- let applicableFilters: SharedFilter[] = []
842
- config.dashboard.sharedFilters.forEach(sharedFilter => {
843
- let allMatch = true
844
- vizKeysUsingDataset.forEach(visualizationKey => {
845
- if (sharedFilter.usedBy && sharedFilter.usedBy.indexOf(visualizationKey) === -1) {
846
- allMatch = false
847
- }
848
- })
849
- if (allMatch) {
850
- applicableFilters.push(sharedFilter)
851
- }
852
- })
853
-
854
- //Applys any applicable filters to the Table
855
- const filteredTableData = applicableFilters.length > 0 ? filterData(applicableFilters, config.datasets[datasetKey].data) : undefined
856
- return (
857
- <div className='multi-table-container' id={`data-table-${datasetKey}`} key={`data-table-${datasetKey}`}>
858
- <DataTable
859
- config={config as TableConfig}
860
- dataConfig={config.datasets[datasetKey]}
861
- rawData={config.datasets[datasetKey].data?.[0]?.tableData || config.datasets[datasetKey].data}
862
- runtimeData={config.datasets[datasetKey].data?.[0]?.tableData || filteredTableData || config.datasets[datasetKey].data || []}
863
- expandDataTable={config.table.expanded}
864
- tableTitle={datasetKey}
865
- viewport={currentViewport}
866
- tabbingId={datasetKey}
867
- />
868
- </div>
869
- )
870
- })}
871
- </div>
721
+ </div>
722
+ </Layout.Responsive>
872
723
  </>
873
724
  )
874
725
  }