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