@cdc/dashboard 4.24.7 → 4.24.9
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 +128394 -122305
- package/examples/single-state-dashboard-filters.json +421 -0
- package/examples/state-level.json +90136 -0
- package/examples/state-points.json +10474 -0
- package/examples/test-file.json +147 -0
- package/examples/testing.json +94456 -0
- package/index.html +18 -6
- package/package.json +9 -9
- package/src/CdcDashboardComponent.tsx +154 -90
- package/src/DashboardContext.tsx +7 -1
- package/src/_stories/Dashboard.stories.tsx +124 -10
- package/src/_stories/_mock/api-filter-map.json +1 -1
- package/src/_stories/_mock/bump-chart.json +3554 -0
- package/src/_stories/_mock/methodology.json +412 -0
- package/src/_stories/_mock/methodologyAPI.ts +90 -0
- package/src/_stories/_mock/multi-viz.json +1 -1
- package/src/_stories/_mock/single-state-dashboard-filters.json +390 -0
- package/src/components/DashboardFilters/DashboardFilters.tsx +39 -17
- package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +2 -2
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +141 -31
- package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +66 -18
- package/src/components/Header/Header.tsx +0 -5
- package/src/components/MultiConfigTabs/MultiConfigTabs.tsx +20 -8
- package/src/components/Row.tsx +1 -1
- package/src/components/VisualizationRow.tsx +98 -17
- package/src/components/Widget.tsx +1 -0
- package/src/helpers/FilterBehavior.ts +4 -0
- package/src/helpers/addValuesToDashboardFilters.ts +49 -0
- package/src/helpers/apiFilterHelpers.ts +69 -18
- package/src/helpers/changeFilterActive.ts +16 -7
- package/src/helpers/getFilteredData.ts +4 -4
- package/src/helpers/iconHash.tsx +2 -0
- package/src/helpers/loadAPIFilters.ts +74 -0
- package/src/helpers/reloadURLHelpers.ts +13 -3
- package/src/helpers/tests/addValuesToDashboardFilters.test.ts +44 -0
- package/src/helpers/tests/apiFilterHelpers.test.ts +156 -0
- package/src/helpers/tests/getFilteredData.test.ts +86 -0
- package/src/helpers/tests/loadAPIFiltersWrapper.test.ts +176 -0
- package/src/helpers/tests/reloadURLHelpers.test.ts +195 -0
- package/src/types/SharedFilter.ts +2 -1
package/index.html
CHANGED
|
@@ -17,24 +17,36 @@
|
|
|
17
17
|
}
|
|
18
18
|
</style>
|
|
19
19
|
<link rel="stylesheet prefetch" href="examples/custom/css/respiratory.css" />
|
|
20
|
-
<link
|
|
20
|
+
<link
|
|
21
|
+
rel="stylesheet prefetch"
|
|
22
|
+
href="https://www.cdc.gov/TemplatePackage/contrib/libs/bootstrap/latest/css/bootstrap.min.css?_=39423"
|
|
23
|
+
/>
|
|
21
24
|
<link rel="stylesheet prefetch" href="https://www.cdc.gov/TemplatePackage/4.0/assets/css/app.min.css?_=39423" />
|
|
22
25
|
</head>
|
|
23
26
|
|
|
24
27
|
<body>
|
|
25
|
-
<div class="react-container" data-config="/examples/
|
|
26
|
-
<div class="react-container" data-config="/examples/
|
|
28
|
+
<!-- <div class="react-container" data-config="/examples/chart-data-2.json"></div> -->
|
|
29
|
+
<!-- <div class="react-container" data-config="/examples/bump-chart.json"></div> -->
|
|
30
|
+
<!-- <div class="react-container" data-config="/examples/full-dashboard.json"></div> -->
|
|
31
|
+
<!-- <div class="react-container" data-config="/examples/dashboard-gallery.json"></div> -->
|
|
32
|
+
<!-- <div class="react-container" data-config="/examples/dev-8332.json"></div> -->
|
|
33
|
+
<!-- <div class="react-container" data-config="/examples/default-multi-dataset.json"></div> -->
|
|
34
|
+
<!-- <div class="react-container" data-config="/examples/dev-8332.json"></div> -->
|
|
27
35
|
<!-- <div class="react-container" data-config="/examples/dashboard-gallery.json"></div> -->
|
|
28
36
|
<!-- <div class="react-container" data-config="/examples/filtered-dash.json"></div> -->
|
|
29
|
-
|
|
37
|
+
<div class="react-container" data-config="/examples/all-components.json"></div>
|
|
30
38
|
<!-- <div class="react-container" data-config="/examples/sankey.json"></div> -->
|
|
31
39
|
<!-- <div class="react-container" data-config="/examples/DEV-6574.json"></div> -->
|
|
32
40
|
<!-- <div class="react-container" data-config="/examples/default-multi-dataset-2.json"></div> -->
|
|
33
|
-
|
|
41
|
+
<div class="react-container" data-config="/examples/default-multi-dataset.json"></div>
|
|
34
42
|
<!-- <div class="react-container" data-config="/examples/default-filter-control.json"></div> -->
|
|
35
43
|
|
|
36
44
|
<!-- Respiratory custom example -->
|
|
37
|
-
<div
|
|
45
|
+
<div
|
|
46
|
+
class="react-container wcms-viz-container"
|
|
47
|
+
data-config-url="/respiratory-viruses/modules/ed-visits-county-file.json"
|
|
48
|
+
data-config="/examples/ed-visits-county-file.json"
|
|
49
|
+
></div>
|
|
38
50
|
|
|
39
51
|
<script src="https://www.cdc.gov/TemplatePackage/contrib/libs/jquery/latest/jquery.min.js?_=91329"></script>
|
|
40
52
|
<!-- <script src="examples/custom/js/respiratory.js"></script> -->
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdc/dashboard",
|
|
3
|
-
"version": "4.24.
|
|
3
|
+
"version": "4.24.9",
|
|
4
4
|
"description": "React component for combining multiple visualizations into a single dashboard",
|
|
5
5
|
"moduleName": "CdcDashboard",
|
|
6
6
|
"main": "dist/cdcdashboard",
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
},
|
|
28
28
|
"license": "Apache-2.0",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@cdc/chart": "^4.24.
|
|
31
|
-
"@cdc/core": "^4.24.
|
|
32
|
-
"@cdc/data-bite": "^4.24.
|
|
33
|
-
"@cdc/filtered-text": "^4.24.
|
|
34
|
-
"@cdc/map": "^4.24.
|
|
35
|
-
"@cdc/markup-include": "^4.24.
|
|
36
|
-
"@cdc/waffle-chart": "^4.24.
|
|
30
|
+
"@cdc/chart": "^4.24.9",
|
|
31
|
+
"@cdc/core": "^4.24.9",
|
|
32
|
+
"@cdc/data-bite": "^4.24.9",
|
|
33
|
+
"@cdc/filtered-text": "^4.24.9",
|
|
34
|
+
"@cdc/map": "^4.24.9",
|
|
35
|
+
"@cdc/markup-include": "^4.24.9",
|
|
36
|
+
"@cdc/waffle-chart": "^4.24.9",
|
|
37
37
|
"html-react-parser": "^3.0.8",
|
|
38
38
|
"js-base64": "^2.5.2",
|
|
39
39
|
"papaparse": "^5.3.0",
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"react": "^18.2.0",
|
|
50
50
|
"react-dom": "^18.2.0"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "c4b0402afe6ed209a85b7078711549b9fd7dae7d"
|
|
53
53
|
}
|
|
@@ -58,13 +58,13 @@ import { getFilteredData } from './helpers/getFilteredData'
|
|
|
58
58
|
import { getVizRowColumnLocator } from './helpers/getVizRowColumnLocator'
|
|
59
59
|
import Layout from '@cdc/core/components/Layout'
|
|
60
60
|
import FootnotesStandAlone from '@cdc/core/components/Footnotes/FootnotesStandAlone'
|
|
61
|
-
import * as apiFilterHelpers from './helpers/apiFilterHelpers'
|
|
62
61
|
import * as reloadURLHelpers from './helpers/reloadURLHelpers'
|
|
63
|
-
import {
|
|
62
|
+
import { addValuesToDashboardFilters } from './helpers/addValuesToDashboardFilters'
|
|
64
63
|
import { DashboardFilters } from './types/DashboardFilters'
|
|
65
64
|
import DashboardSharedFilters from './components/DashboardFilters'
|
|
66
65
|
import ExpandCollapseButtons from './components/ExpandCollapseButtons'
|
|
67
66
|
import { hasDashboardApplyBehavior } from './helpers/hasDashboardApplyBehavior'
|
|
67
|
+
import { loadAPIFiltersFactory } from './helpers/loadAPIFilters'
|
|
68
68
|
|
|
69
69
|
type DashboardProps = Omit<WCMSProps, 'configUrl'> & {
|
|
70
70
|
initialState: InitialState
|
|
@@ -96,64 +96,7 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
96
96
|
.reduce((acc, viz: DashboardFilters) => (viz.autoLoad ? [...acc, ...viz.sharedFilterIndexes] : acc), [])
|
|
97
97
|
}, [state.config.visualizations])
|
|
98
98
|
|
|
99
|
-
const
|
|
100
|
-
const sharedFilter = _.cloneDeep(sharedFilters[sharedFilterIndex])
|
|
101
|
-
if (!autoLoadFilterIndexes.length || !dropdownOptions) return sharedFilter // no autoLoading happening
|
|
102
|
-
if (!sharedFilter.active && autoLoadFilterIndexes.includes(sharedFilterIndex)) {
|
|
103
|
-
const filterParents = sharedFilters.filter(f => sharedFilter.parents?.includes(f.key))
|
|
104
|
-
const notAllParentFiltersSelected = filterParents.some(p => !(p.active || p.queuedActive))
|
|
105
|
-
if (filterParents && notAllParentFiltersSelected) return sharedFilter
|
|
106
|
-
// TODO get default value from query parameter
|
|
107
|
-
const defaultValue = dropdownOptions[0].value
|
|
108
|
-
sharedFilter.active = defaultValue
|
|
109
|
-
}
|
|
110
|
-
return sharedFilter
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const loadAPIFilters = (sharedFilters: SharedFilter[], dropdowns = apiFilterDropdowns, recursiveLimit = 3): Promise<SharedFilter[]> => {
|
|
114
|
-
if (!sharedFilters) return
|
|
115
|
-
sharedFilters = sharedFilters.map((filter, index) => setAutoLoadDefaultValue(index, dropdowns[filter.apiFilter?.apiEndpoint], sharedFilters))
|
|
116
|
-
const sharedAPIFilters = sharedFilters.filter(f => f.apiFilter)
|
|
117
|
-
const loadingFilterMemo = apiFilterHelpers.getLoadingFilterMemo(sharedAPIFilters, dropdowns)
|
|
118
|
-
setAPIFilterDropdowns({ ...dropdowns, ...loadingFilterMemo })
|
|
119
|
-
const filterLookup = new Map(sharedAPIFilters.map(filter => [filter.apiFilter.apiEndpoint, filter.apiFilter]))
|
|
120
|
-
const toFetch = apiFilterHelpers.getToFetch(sharedAPIFilters, dropdowns)
|
|
121
|
-
const newDropdowns = _.cloneDeep(dropdowns)
|
|
122
|
-
return Promise.all(
|
|
123
|
-
Object.keys(toFetch).map(
|
|
124
|
-
endpoint =>
|
|
125
|
-
new Promise<void>(resolve => {
|
|
126
|
-
fetch(endpoint)
|
|
127
|
-
.then(resp => resp.json())
|
|
128
|
-
.then(data => {
|
|
129
|
-
const [_key, index] = toFetch[endpoint]
|
|
130
|
-
if (!Array.isArray(data)) throw new Error('COVE only supports response data in the shape Array<Object>')
|
|
131
|
-
const apiFilter = filterLookup.get(_key) as APIFilter
|
|
132
|
-
const _filterValues = apiFilterHelpers.getFilterValues(data, apiFilter)
|
|
133
|
-
newDropdowns[_key] = _filterValues
|
|
134
|
-
const newDefaultSelectedFilter = setAutoLoadDefaultValue(index, _filterValues, sharedFilters)
|
|
135
|
-
sharedFilters[index] = newDefaultSelectedFilter
|
|
136
|
-
})
|
|
137
|
-
.catch(console.error)
|
|
138
|
-
.finally(() => {
|
|
139
|
-
resolve()
|
|
140
|
-
})
|
|
141
|
-
})
|
|
142
|
-
)
|
|
143
|
-
).then(() => {
|
|
144
|
-
const finishedLoading = sharedFilters.reduce((acc, curr, index) => {
|
|
145
|
-
if (autoLoadFilterIndexes.includes(index) && !curr.active) return false
|
|
146
|
-
return acc
|
|
147
|
-
}, true)
|
|
148
|
-
if (finishedLoading || recursiveLimit === 0) {
|
|
149
|
-
setAPIFilterDropdowns(dropdowns => ({ ...dropdowns, ...newDropdowns }))
|
|
150
|
-
dispatch({ type: 'SET_SHARED_FILTERS', payload: sharedFilters })
|
|
151
|
-
return sharedFilters
|
|
152
|
-
} else {
|
|
153
|
-
return loadAPIFilters(sharedFilters, newDropdowns, recursiveLimit - 1)
|
|
154
|
-
}
|
|
155
|
-
})
|
|
156
|
-
}
|
|
99
|
+
const loadAPIFilters = loadAPIFiltersFactory(dispatch, setAPIFilterDropdowns, autoLoadFilterIndexes)
|
|
157
100
|
|
|
158
101
|
const reloadURLData = async (newFilters?: SharedFilter[]) => {
|
|
159
102
|
const config = _.cloneDeep(state.config)
|
|
@@ -175,8 +118,10 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
175
118
|
const currentQSParams = Object.fromEntries(new URLSearchParams(dataUrl.search))
|
|
176
119
|
const updatedQSParams = {}
|
|
177
120
|
filters.forEach(filter => {
|
|
178
|
-
|
|
179
|
-
|
|
121
|
+
if (
|
|
122
|
+
filter.type === 'urlfilter' &&
|
|
123
|
+
reloadURLHelpers.filterUsedByDataUrl(filter, datasetKey, config.visualizations)
|
|
124
|
+
) {
|
|
180
125
|
if (filter.filterBy === 'File Name') {
|
|
181
126
|
newFileName = reloadURLHelpers.getNewFileName(newFileName, filter, datasetKey)
|
|
182
127
|
}
|
|
@@ -197,7 +142,11 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
197
142
|
|
|
198
143
|
if (!!newFilters || reloadURLHelpers.isUpdateNeeded(filters, currentQSParams, updatedQSParams)) {
|
|
199
144
|
dataWasFetched = true
|
|
200
|
-
const dataUrlFinal = reloadURLHelpers.getDataURL(
|
|
145
|
+
const dataUrlFinal = reloadURLHelpers.getDataURL(
|
|
146
|
+
{ ...currentQSParams, ...updatedQSParams },
|
|
147
|
+
dataUrl,
|
|
148
|
+
newFileName
|
|
149
|
+
)
|
|
201
150
|
|
|
202
151
|
await fetchRemoteData(dataUrlFinal).then(responseData => {
|
|
203
152
|
let data: any[] = responseData
|
|
@@ -219,9 +168,15 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
219
168
|
|
|
220
169
|
if (dataWasFetched) {
|
|
221
170
|
dispatch({ type: 'SET_DATA', payload: newData })
|
|
222
|
-
const filtersWithNewValues =
|
|
223
|
-
const dashboardConfig = newFilters
|
|
224
|
-
|
|
171
|
+
const filtersWithNewValues = addValuesToDashboardFilters(filters, newData)
|
|
172
|
+
const dashboardConfig = newFilters
|
|
173
|
+
? { ...config.dashboard, sharedFilters: filtersWithNewValues }
|
|
174
|
+
: config.dashboard
|
|
175
|
+
const filteredData = getFilteredData(
|
|
176
|
+
{ ...state, config: { ...state.config, dashboard: dashboardConfig } },
|
|
177
|
+
{},
|
|
178
|
+
newData
|
|
179
|
+
)
|
|
225
180
|
dispatch({ type: 'SET_FILTERED_DATA', payload: filteredData })
|
|
226
181
|
const visualizations = reloadURLHelpers.getVisualizationsWithFormattedData(config.visualizations, newData)
|
|
227
182
|
dispatch({ type: 'SET_CONFIG', payload: { dashboard: dashboardConfig, datasets: newDatasets, visualizations } })
|
|
@@ -265,9 +220,9 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
265
220
|
reloadURLData()
|
|
266
221
|
}
|
|
267
222
|
|
|
268
|
-
const sharedFiltersWithValues =
|
|
269
|
-
loadAPIFilters(sharedFiltersWithValues)
|
|
270
|
-
updateFilteredData()
|
|
223
|
+
const sharedFiltersWithValues = addValuesToDashboardFilters(config.dashboard.sharedFilters, state.data)
|
|
224
|
+
loadAPIFilters(sharedFiltersWithValues, apiFilterDropdowns)
|
|
225
|
+
updateFilteredData(sharedFiltersWithValues)
|
|
271
226
|
}, [isEditor, isPreview, state.config?.activeDashboard])
|
|
272
227
|
|
|
273
228
|
const updateChildConfig = (visualizationKey, newConfig) => {
|
|
@@ -322,17 +277,29 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
322
277
|
|
|
323
278
|
getVizKeys(state.config).forEach(visualizationKey => {
|
|
324
279
|
const rowNumber = vizRowColumnLocator[visualizationKey]?.row
|
|
325
|
-
const visualizationConfig = getVizConfig(
|
|
280
|
+
const visualizationConfig = getVizConfig(
|
|
281
|
+
visualizationKey,
|
|
282
|
+
rowNumber,
|
|
283
|
+
state.config,
|
|
284
|
+
state.data,
|
|
285
|
+
state.filteredData
|
|
286
|
+
)
|
|
326
287
|
visualizationConfig.uid = visualizationKey
|
|
327
288
|
if (visualizationConfig.type === 'footnotes') visualizationConfig.formattedData = undefined
|
|
328
|
-
const setsSharedFilter =
|
|
329
|
-
|
|
289
|
+
const setsSharedFilter =
|
|
290
|
+
state.config.dashboard.sharedFilters &&
|
|
291
|
+
state.config.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.setBy === visualizationKey).length > 0
|
|
292
|
+
const setSharedFilterValue = setsSharedFilter
|
|
293
|
+
? state.config.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.setBy === visualizationKey)[0].active
|
|
294
|
+
: undefined
|
|
330
295
|
|
|
331
296
|
if (visualizationConfig.editing) {
|
|
332
297
|
subVisualizationEditing = true
|
|
333
298
|
|
|
334
299
|
const _updateConfig = newConfig => {
|
|
335
|
-
let dataCorrectedConfig = visualizationConfig.originalFormattedData
|
|
300
|
+
let dataCorrectedConfig = visualizationConfig.originalFormattedData
|
|
301
|
+
? { ...newConfig, formattedData: visualizationConfig.originalFormattedData }
|
|
302
|
+
: newConfig
|
|
336
303
|
updateChildConfig(visualizationKey, dataCorrectedConfig)
|
|
337
304
|
}
|
|
338
305
|
|
|
@@ -382,7 +349,13 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
382
349
|
body = (
|
|
383
350
|
<>
|
|
384
351
|
<Header visualizationKey={visualizationKey} subEditor='Data Bite' />
|
|
385
|
-
<CdcDataBite
|
|
352
|
+
<CdcDataBite
|
|
353
|
+
key={visualizationKey}
|
|
354
|
+
config={{ ...visualizationConfig, newViz: true }}
|
|
355
|
+
isEditor={true}
|
|
356
|
+
setConfig={_updateConfig}
|
|
357
|
+
isDashboard={true}
|
|
358
|
+
/>
|
|
386
359
|
</>
|
|
387
360
|
)
|
|
388
361
|
break
|
|
@@ -390,7 +363,14 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
390
363
|
body = (
|
|
391
364
|
<>
|
|
392
365
|
<Header visualizationKey={visualizationKey} subEditor='Waffle Chart' />
|
|
393
|
-
<CdcWaffleChart
|
|
366
|
+
<CdcWaffleChart
|
|
367
|
+
key={visualizationKey}
|
|
368
|
+
config={visualizationConfig}
|
|
369
|
+
isEditor={true}
|
|
370
|
+
setConfig={_updateConfig}
|
|
371
|
+
isDashboard={true}
|
|
372
|
+
configUrl={undefined}
|
|
373
|
+
/>
|
|
394
374
|
</>
|
|
395
375
|
)
|
|
396
376
|
break
|
|
@@ -398,7 +378,14 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
398
378
|
body = (
|
|
399
379
|
<>
|
|
400
380
|
<Header visualizationKey={visualizationKey} subEditor='Markup Include' />
|
|
401
|
-
<CdcMarkupInclude
|
|
381
|
+
<CdcMarkupInclude
|
|
382
|
+
key={visualizationKey}
|
|
383
|
+
config={visualizationConfig}
|
|
384
|
+
isEditor={true}
|
|
385
|
+
setConfig={_updateConfig}
|
|
386
|
+
isDashboard={true}
|
|
387
|
+
configUrl={undefined}
|
|
388
|
+
/>
|
|
402
389
|
</>
|
|
403
390
|
)
|
|
404
391
|
break
|
|
@@ -406,7 +393,14 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
406
393
|
body = (
|
|
407
394
|
<>
|
|
408
395
|
<Header visualizationKey={visualizationKey} subEditor='Filtered Text' />
|
|
409
|
-
<CdcFilteredText
|
|
396
|
+
<CdcFilteredText
|
|
397
|
+
key={visualizationKey}
|
|
398
|
+
config={visualizationConfig}
|
|
399
|
+
isEditor={true}
|
|
400
|
+
setConfig={_updateConfig}
|
|
401
|
+
isDashboard={true}
|
|
402
|
+
configUrl={undefined}
|
|
403
|
+
/>
|
|
410
404
|
</>
|
|
411
405
|
)
|
|
412
406
|
break
|
|
@@ -415,7 +409,12 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
415
409
|
body = !hideFilter ? (
|
|
416
410
|
<>
|
|
417
411
|
<Header visualizationKey={visualizationKey} subEditor='Filter Dropdowns' />
|
|
418
|
-
<DashboardSharedFilters
|
|
412
|
+
<DashboardSharedFilters
|
|
413
|
+
isEditor={true}
|
|
414
|
+
visualizationConfig={visualizationConfig}
|
|
415
|
+
apiFilterDropdowns={apiFilterDropdowns}
|
|
416
|
+
setConfig={_updateConfig}
|
|
417
|
+
/>
|
|
419
418
|
</>
|
|
420
419
|
) : (
|
|
421
420
|
<></>
|
|
@@ -425,7 +424,12 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
425
424
|
body = (
|
|
426
425
|
<>
|
|
427
426
|
<Header visualizationKey={visualizationKey} subEditor='Table' />
|
|
428
|
-
<DataTableStandAlone
|
|
427
|
+
<DataTableStandAlone
|
|
428
|
+
visualizationKey={visualizationKey}
|
|
429
|
+
config={visualizationConfig}
|
|
430
|
+
isEditor={true}
|
|
431
|
+
updateConfig={_updateConfig}
|
|
432
|
+
/>
|
|
429
433
|
</>
|
|
430
434
|
)
|
|
431
435
|
break
|
|
@@ -433,10 +437,14 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
433
437
|
body = (
|
|
434
438
|
<>
|
|
435
439
|
<Header visualizationKey={visualizationKey} subEditor='Footnotes' />
|
|
436
|
-
<FootnotesStandAlone
|
|
440
|
+
<FootnotesStandAlone
|
|
441
|
+
visualizationKey={visualizationKey}
|
|
442
|
+
config={{ ...visualizationConfig, datasets: state.config.datasets }}
|
|
443
|
+
isEditor={true}
|
|
444
|
+
updateConfig={_updateConfig}
|
|
445
|
+
/>
|
|
437
446
|
</>
|
|
438
447
|
)
|
|
439
|
-
break
|
|
440
448
|
default:
|
|
441
449
|
body = <></>
|
|
442
450
|
break
|
|
@@ -468,7 +476,11 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
468
476
|
<MultiTabs isEditor={isEditor && !isPreview} />
|
|
469
477
|
<Layout.Responsive isEditor={isEditor}>
|
|
470
478
|
<div className={`cdc-dashboard-inner-container${isEditor ? ' is-editor' : ''}`}>
|
|
471
|
-
<Title
|
|
479
|
+
<Title
|
|
480
|
+
title={title}
|
|
481
|
+
isDashboard={true}
|
|
482
|
+
classes={[`dashboard-title`, `${config.dashboard.theme ?? 'theme-blue'}`]}
|
|
483
|
+
/>
|
|
472
484
|
{/* Description */}
|
|
473
485
|
{description && <div className='subtext'>{parse(description)}</div>}
|
|
474
486
|
{/* Visualizations */}
|
|
@@ -488,7 +500,9 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
488
500
|
return (
|
|
489
501
|
<>
|
|
490
502
|
{/* Expand/Collapse All */}
|
|
491
|
-
{row.expandCollapseAllButtons === true &&
|
|
503
|
+
{row.expandCollapseAllButtons === true && (
|
|
504
|
+
<ExpandCollapseButtons setAllExpanded={setAllExpanded} />
|
|
505
|
+
)}
|
|
492
506
|
{Object.keys(dataGroups).map(groupName => {
|
|
493
507
|
const dataValue = dataGroups[groupName]
|
|
494
508
|
return (
|
|
@@ -509,14 +523,42 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
509
523
|
</>
|
|
510
524
|
)
|
|
511
525
|
} else {
|
|
512
|
-
return
|
|
526
|
+
return (
|
|
527
|
+
<VisualizationRow
|
|
528
|
+
key={`row__${index}`}
|
|
529
|
+
allExpanded={false}
|
|
530
|
+
groupName={''}
|
|
531
|
+
row={row}
|
|
532
|
+
rowIndex={index}
|
|
533
|
+
setSharedFilter={setSharedFilter}
|
|
534
|
+
updateChildConfig={updateChildConfig}
|
|
535
|
+
apiFilterDropdowns={apiFilterDropdowns}
|
|
536
|
+
currentViewport={currentViewport}
|
|
537
|
+
/>
|
|
538
|
+
)
|
|
513
539
|
}
|
|
514
540
|
})}
|
|
515
541
|
|
|
516
542
|
{/* Image or PDF Inserts */}
|
|
517
543
|
<section className='download-buttons'>
|
|
518
|
-
{config.table?.downloadImageButton &&
|
|
519
|
-
|
|
544
|
+
{config.table?.downloadImageButton && (
|
|
545
|
+
<MediaControls.Button
|
|
546
|
+
title='Download Dashboard as Image'
|
|
547
|
+
type='image'
|
|
548
|
+
state={config}
|
|
549
|
+
text='Download Dashboard Image'
|
|
550
|
+
elementToCapture={imageId}
|
|
551
|
+
/>
|
|
552
|
+
)}
|
|
553
|
+
{config.table?.downloadPdfButton && (
|
|
554
|
+
<MediaControls.Button
|
|
555
|
+
title='Download Dashboard as PDF'
|
|
556
|
+
type='pdf'
|
|
557
|
+
state={config}
|
|
558
|
+
text='Download Dashboard PDF'
|
|
559
|
+
elementToCapture={imageId}
|
|
560
|
+
/>
|
|
561
|
+
)}
|
|
520
562
|
</section>
|
|
521
563
|
|
|
522
564
|
{/* Data Table */}
|
|
@@ -561,14 +603,26 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
561
603
|
})
|
|
562
604
|
|
|
563
605
|
//Applys any applicable filters to the Table
|
|
564
|
-
const filteredTableData =
|
|
606
|
+
const filteredTableData =
|
|
607
|
+
applicableFilters.length > 0
|
|
608
|
+
? filterData(applicableFilters, config.datasets[datasetKey].data)
|
|
609
|
+
: undefined
|
|
565
610
|
return (
|
|
566
|
-
<div
|
|
611
|
+
<div
|
|
612
|
+
className='multi-table-container'
|
|
613
|
+
id={`data-table-${datasetKey}`}
|
|
614
|
+
key={`data-table-${datasetKey}`}
|
|
615
|
+
>
|
|
567
616
|
<DataTable
|
|
568
617
|
config={config as TableConfig}
|
|
569
618
|
dataConfig={config.datasets[datasetKey]}
|
|
570
619
|
rawData={config.datasets[datasetKey].data?.[0]?.tableData || config.datasets[datasetKey].data}
|
|
571
|
-
runtimeData={
|
|
620
|
+
runtimeData={
|
|
621
|
+
config.datasets[datasetKey].data?.[0]?.tableData ||
|
|
622
|
+
filteredTableData ||
|
|
623
|
+
config.datasets[datasetKey].data ||
|
|
624
|
+
[]
|
|
625
|
+
}
|
|
572
626
|
expandDataTable={config.table.expanded}
|
|
573
627
|
tableTitle={datasetKey}
|
|
574
628
|
viewport={currentViewport}
|
|
@@ -587,7 +641,17 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
|
|
|
587
641
|
|
|
588
642
|
return (
|
|
589
643
|
<GlobalContextProvider>
|
|
590
|
-
<DashboardContext.Provider
|
|
644
|
+
<DashboardContext.Provider
|
|
645
|
+
value={{
|
|
646
|
+
...state,
|
|
647
|
+
setParentConfig: editorContext.setTempConfig,
|
|
648
|
+
outerContainerRef,
|
|
649
|
+
isDebug,
|
|
650
|
+
loadAPIFilters,
|
|
651
|
+
setAPIFilterDropdowns,
|
|
652
|
+
reloadURLData
|
|
653
|
+
}}
|
|
654
|
+
>
|
|
591
655
|
<DashboardDispatchContext.Provider value={dispatch}>
|
|
592
656
|
<div className={dashboardContainerClasses.join(' ')} ref={outerContainerRef} data-download-id={imageId}>
|
|
593
657
|
{body}
|
package/src/DashboardContext.tsx
CHANGED
|
@@ -11,7 +11,12 @@ type ConfigCTX = DashboardState & {
|
|
|
11
11
|
setParentConfig: any
|
|
12
12
|
isDebug: boolean
|
|
13
13
|
reloadURLData: (newFilters?: SharedFilter[]) => void
|
|
14
|
-
loadAPIFilters: (
|
|
14
|
+
loadAPIFilters: (
|
|
15
|
+
sharedFilters: SharedFilter[],
|
|
16
|
+
dropdowns: APIFilterDropdowns,
|
|
17
|
+
recursiveLimit?: number
|
|
18
|
+
) => Promise<SharedFilter[]>
|
|
19
|
+
setAPIFilterDropdowns: (dropdowns: APIFilterDropdowns) => void
|
|
15
20
|
}
|
|
16
21
|
|
|
17
22
|
const firstTab: Tab = 'Dashboard Description'
|
|
@@ -27,6 +32,7 @@ export const initialState = {
|
|
|
27
32
|
const initialContext: ConfigCTX = {
|
|
28
33
|
outerContainerRef: () => {},
|
|
29
34
|
setParentConfig: () => {},
|
|
35
|
+
setAPIFilterDropdowns: () => {},
|
|
30
36
|
reloadURLData: () => {},
|
|
31
37
|
loadAPIFilters: () => Promise.resolve([]),
|
|
32
38
|
isDebug: false,
|