@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.
- package/dist/cdcdashboard.js +148123 -105018
- package/examples/chart-data.json +5409 -0
- package/examples/full-dash-test.json +14643 -0
- package/examples/full-dashboard.json +10036 -0
- package/index.html +2 -2
- package/package.json +9 -9
- package/src/CdcDashboard.tsx +8 -3
- package/src/CdcDashboardComponent.tsx +141 -290
- package/src/_stories/Dashboard.stories.tsx +52 -7
- package/src/_stories/_mock/markup-include.json +78 -0
- package/src/_stories/_mock/multi-dashboards.json +914 -0
- package/src/_stories/_mock/multi-viz.json +378 -0
- package/src/_stories/_mock/pivot-filter.json +2 -2
- package/src/_stories/_mock/standalone-table.json +2 -0
- package/src/components/DataDesignerModal.tsx +145 -0
- package/src/components/Grid.tsx +3 -1
- package/src/components/Header/FilterModal.tsx +63 -33
- package/src/components/MultiConfigTabs/MultiTabs.tsx +3 -2
- package/src/components/Row.tsx +50 -25
- package/src/components/Toggle/Toggle.tsx +6 -7
- package/src/components/VisualizationRow.tsx +183 -0
- package/src/components/VisualizationsPanel.tsx +26 -3
- package/src/components/Widget.tsx +21 -103
- package/src/helpers/filterData.ts +1 -1
- package/src/helpers/getFilteredData.ts +39 -0
- package/src/helpers/getUpdateConfig.ts +15 -0
- package/src/helpers/getVizConfig.ts +31 -0
- package/src/helpers/getVizRowColumnLocator.ts +9 -0
- package/src/scss/grid.scss +9 -2
- package/src/scss/main.scss +5 -0
- package/src/store/dashboard.actions.ts +6 -0
- package/src/store/dashboard.reducer.ts +33 -8
- package/src/types/ConfigRow.ts +12 -3
- package/src/types/DataSet.ts +11 -8
- package/src/types/SharedFilter.ts +1 -1
- package/src/components/EditorWrapper/EditorWrapper.tsx +0 -52
- 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
|
-
|
|
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
|
+
"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.
|
|
30
|
-
"@cdc/core": "^4.24.
|
|
31
|
-
"@cdc/data-bite": "^4.24.
|
|
32
|
-
"@cdc/filtered-text": "^4.24.
|
|
33
|
-
"@cdc/map": "^4.24.
|
|
34
|
-
"@cdc/markup-include": "^4.24.
|
|
35
|
-
"@cdc/waffle-chart": "^4.24.
|
|
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": "
|
|
51
|
+
"gitHead": "def85aaf4cd9dc1983e80f2900199f35de82af95"
|
|
52
52
|
}
|
package/src/CdcDashboard.tsx
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
64
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
}, [
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
620
|
-
<
|
|
621
|
-
|
|
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
|
-
<
|
|
653
|
-
<
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
config.rows
|
|
668
|
-
.
|
|
669
|
-
|
|
670
|
-
|
|
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=
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
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
|
-
|
|
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
|
}
|