@cdc/dashboard 4.24.2 → 4.24.4
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 +128512 -99417
- package/examples/chart-data.json +5409 -0
- package/examples/full-dash-test.json +14643 -0
- package/examples/full-dashboard.json +10036 -0
- package/examples/sankey.json +5218 -0
- package/index.html +4 -3
- package/package.json +11 -10
- package/src/CdcDashboard.tsx +129 -124
- package/src/CdcDashboardComponent.tsx +316 -441
- package/src/DashboardContext.tsx +4 -1
- package/src/_stories/Dashboard.stories.tsx +79 -36
- package/src/_stories/_mock/api-filter-chart.json +11 -35
- package/src/_stories/_mock/api-filter-map.json +17 -31
- package/src/_stories/_mock/dashboard-gallery.json +523 -534
- package/src/_stories/_mock/multi-viz.json +378 -0
- package/src/_stories/_mock/pivot-filter.json +161 -0
- package/src/_stories/_mock/standalone-table.json +122 -0
- package/src/_stories/_mock/toggle-example.json +4035 -0
- package/src/components/DataDesignerModal.tsx +145 -0
- package/src/components/EditorWrapper/EditorWrapper.tsx +52 -0
- package/src/components/EditorWrapper/editor-wrapper.style.css +13 -0
- package/src/components/Filters.tsx +88 -0
- package/src/components/Grid.tsx +3 -1
- package/src/components/Header/FilterModal.tsx +506 -0
- package/src/components/Header/Header.tsx +25 -465
- package/src/components/Row.tsx +65 -29
- package/src/components/Toggle/Toggle.tsx +36 -0
- package/src/components/Toggle/index.tsx +1 -0
- package/src/components/Toggle/toggle-style.css +34 -0
- package/src/components/VisualizationRow.tsx +174 -0
- package/src/components/VisualizationsPanel.tsx +13 -3
- package/src/components/Widget.tsx +28 -126
- package/src/helpers/filterData.ts +75 -50
- package/src/helpers/generateValuesForFilter.ts +2 -12
- package/src/helpers/getApiFilterKey.ts +5 -0
- package/src/helpers/getFilteredData.ts +39 -0
- package/src/helpers/getUpdateConfig.ts +39 -22
- package/src/helpers/getVizConfig.ts +31 -0
- package/src/helpers/getVizRowColumnLocator.ts +9 -0
- package/src/helpers/iconHash.tsx +34 -0
- package/src/helpers/tests/filterData.test.ts +149 -0
- package/src/images/icon-toggle.svg +1 -0
- package/src/scss/grid.scss +10 -3
- package/src/scss/main.scss +11 -0
- package/src/store/dashboard.actions.ts +35 -3
- package/src/store/dashboard.reducer.ts +33 -2
- package/src/types/APIFilter.ts +4 -5
- package/src/types/ConfigRow.ts +13 -2
- package/src/types/DataSet.ts +11 -8
- package/src/types/InitialState.ts +2 -1
- package/src/types/SharedFilter.ts +6 -3
- package/src/types/Tab.ts +1 -0
package/index.html
CHANGED
|
@@ -21,11 +21,12 @@
|
|
|
21
21
|
</head>
|
|
22
22
|
|
|
23
23
|
<body>
|
|
24
|
-
<div class="react-container" data-config="/examples/
|
|
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
|
-
<div class="react-container" data-config="/examples/
|
|
28
|
+
<!-- <div class="react-container" data-config="/examples/sankey.json"></div> -->
|
|
29
|
+
<div class="react-container" data-config="/examples/DEV-6574.json"></div>
|
|
29
30
|
<!-- <div class="react-container" data-config="/examples/default-multi-dataset-2.json"></div> -->
|
|
30
31
|
<!-- <div class="react-container" data-config="/examples/default-multi-dataset.json"></div> -->
|
|
31
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.4",
|
|
4
4
|
"description": "React component for combining multiple visualizations into a single dashboard",
|
|
5
5
|
"moduleName": "CdcDashboard",
|
|
6
6
|
"main": "dist/cdcdashboard",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"graph": "nx graph",
|
|
13
13
|
"prepublishOnly": "lerna run --scope @cdc/dashboard build",
|
|
14
14
|
"test": "vitest watch --reporter verbose",
|
|
15
|
-
"test:ui": "vitest --ui"
|
|
15
|
+
"test:ui": "vitest --ui",
|
|
16
|
+
"coverage": "vitest run --coverage"
|
|
16
17
|
},
|
|
17
18
|
"repository": {
|
|
18
19
|
"type": "git",
|
|
@@ -25,13 +26,13 @@
|
|
|
25
26
|
},
|
|
26
27
|
"license": "Apache-2.0",
|
|
27
28
|
"dependencies": {
|
|
28
|
-
"@cdc/chart": "^4.24.
|
|
29
|
-
"@cdc/core": "^4.24.
|
|
30
|
-
"@cdc/data-bite": "^4.24.
|
|
31
|
-
"@cdc/filtered-text": "^4.24.
|
|
32
|
-
"@cdc/map": "^4.24.
|
|
33
|
-
"@cdc/markup-include": "^4.24.
|
|
34
|
-
"@cdc/waffle-chart": "^4.24.
|
|
29
|
+
"@cdc/chart": "^4.24.4",
|
|
30
|
+
"@cdc/core": "^4.24.4",
|
|
31
|
+
"@cdc/data-bite": "^4.24.4",
|
|
32
|
+
"@cdc/filtered-text": "^4.24.4",
|
|
33
|
+
"@cdc/map": "^4.24.4",
|
|
34
|
+
"@cdc/markup-include": "^4.24.4",
|
|
35
|
+
"@cdc/waffle-chart": "^4.24.4",
|
|
35
36
|
"html-react-parser": "^3.0.8",
|
|
36
37
|
"js-base64": "^2.5.2",
|
|
37
38
|
"papaparse": "^5.3.0",
|
|
@@ -47,5 +48,5 @@
|
|
|
47
48
|
"react": "^18.2.0",
|
|
48
49
|
"react-dom": "^18.2.0"
|
|
49
50
|
},
|
|
50
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "1843b4632140d582af6a87606374cbd4fe25ad5c"
|
|
51
52
|
}
|
package/src/CdcDashboard.tsx
CHANGED
|
@@ -1,124 +1,129 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react'
|
|
2
|
-
import CdcDashboard from './CdcDashboardComponent'
|
|
3
|
-
import { MultiDashboardConfig } from './types/MultiDashboard'
|
|
4
|
-
import Loading from '@cdc/core/components/Loading'
|
|
5
|
-
import defaults from './data/initial-state'
|
|
6
|
-
import { processData } from './helpers/processData'
|
|
7
|
-
import { getVizKeys } from './helpers/getVizKeys'
|
|
8
|
-
import { processDataLegacy } from './helpers/processDataLegacy'
|
|
9
|
-
import { WCMSProps } from '@cdc/core/types/WCMSProps'
|
|
10
|
-
import { initialState } from './DashboardContext'
|
|
11
|
-
import { getUpdateConfig } from './helpers/getUpdateConfig'
|
|
12
|
-
import { InitialState } from './types/InitialState'
|
|
13
|
-
import { DashboardConfig } from './types/DashboardConfig'
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const getSelectedConfig = (config: MultiDashboardConfig, selectedConfig?: string): number | null => {
|
|
26
|
-
if (!config.multiDashboards) return null
|
|
27
|
-
// TODO: if query parameter select based on query parameter
|
|
28
|
-
if (selectedConfig) {
|
|
29
|
-
const foundConfig = Object.values(config.multiDashboards).findIndex(({ label }) => {
|
|
30
|
-
return label === selectedConfig
|
|
31
|
-
})
|
|
32
|
-
if (foundConfig > -1) return foundConfig
|
|
33
|
-
}
|
|
34
|
-
// else select the first available
|
|
35
|
-
return 0
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const formatInitialState = (newConfig: MultiDashboardConfig | DashboardConfig, datasets: Record<string, Object[]>) => {
|
|
39
|
-
const [config, filteredData] = getUpdateConfig(initialState)(newConfig, datasets)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
let
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
import CdcDashboard from './CdcDashboardComponent'
|
|
3
|
+
import { MultiDashboardConfig } from './types/MultiDashboard'
|
|
4
|
+
import Loading from '@cdc/core/components/Loading'
|
|
5
|
+
import defaults from './data/initial-state'
|
|
6
|
+
import { processData } from './helpers/processData'
|
|
7
|
+
import { getVizKeys } from './helpers/getVizKeys'
|
|
8
|
+
import { processDataLegacy } from './helpers/processDataLegacy'
|
|
9
|
+
import { WCMSProps } from '@cdc/core/types/WCMSProps'
|
|
10
|
+
import { initialState } from './DashboardContext'
|
|
11
|
+
import { getUpdateConfig } from './helpers/getUpdateConfig'
|
|
12
|
+
import { InitialState } from './types/InitialState'
|
|
13
|
+
import { DashboardConfig } from './types/DashboardConfig'
|
|
14
|
+
import { coveUpdateWorker } from '@cdc/core/helpers/coveUpdateWorker'
|
|
15
|
+
import _ from 'lodash'
|
|
16
|
+
|
|
17
|
+
type MultiDashboardProps = Omit<WCMSProps, 'configUrl'> & {
|
|
18
|
+
configUrl?: string
|
|
19
|
+
config?: MultiDashboardConfig
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const MultiDashboardWrapper: React.FC<MultiDashboardProps> = ({ configUrl, config: editorConfig, isEditor, isDebug }) => {
|
|
23
|
+
const [initial, setInitial] = useState<InitialState>(undefined)
|
|
24
|
+
|
|
25
|
+
const getSelectedConfig = (config: MultiDashboardConfig, selectedConfig?: string): number | null => {
|
|
26
|
+
if (!config.multiDashboards) return null
|
|
27
|
+
// TODO: if query parameter select based on query parameter
|
|
28
|
+
if (selectedConfig) {
|
|
29
|
+
const foundConfig = Object.values(config.multiDashboards).findIndex(({ label }) => {
|
|
30
|
+
return label === selectedConfig
|
|
31
|
+
})
|
|
32
|
+
if (foundConfig > -1) return foundConfig
|
|
33
|
+
}
|
|
34
|
+
// else select the first available
|
|
35
|
+
return 0
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const formatInitialState = (newConfig: MultiDashboardConfig | DashboardConfig, datasets: Record<string, Object[]>) => {
|
|
39
|
+
const [config, filteredData] = getUpdateConfig(initialState)(newConfig, datasets)
|
|
40
|
+
const versionedConfig = coveUpdateWorker(config)
|
|
41
|
+
return { ...initialState, config: versionedConfig, filteredData, data: datasets }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const loadConfig = async (selectedConfig?: string) => {
|
|
45
|
+
const _config: MultiDashboardConfig = editorConfig || (await (await fetch(configUrl)).json())
|
|
46
|
+
const selected = getSelectedConfig(_config, selectedConfig)
|
|
47
|
+
|
|
48
|
+
const { newConfig, datasets } = selected !== null ? await loadMultiDashboard(_config, selected) : await loadSingleDashboard(_config)
|
|
49
|
+
setInitial(formatInitialState(newConfig, datasets))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
loadConfig()
|
|
54
|
+
}, [])
|
|
55
|
+
|
|
56
|
+
const loadData = async (initialConfig: DashboardConfig | MultiDashboardConfig) => {
|
|
57
|
+
let newConfig = { ...initialConfig }
|
|
58
|
+
let datasets: Record<string, Object[]> = {}
|
|
59
|
+
await Promise.all(
|
|
60
|
+
Object.keys(initialConfig.datasets).map(async key => {
|
|
61
|
+
const data = await processData(initialConfig.datasets[key], initialConfig.filterBehavior)
|
|
62
|
+
datasets[key] = data || []
|
|
63
|
+
})
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
getVizKeys(newConfig).forEach(vizKey => {
|
|
67
|
+
const formattedData = datasets[newConfig.visualizations[vizKey].dataKey]
|
|
68
|
+
if (formattedData) {
|
|
69
|
+
newConfig.visualizations[vizKey].formattedData = formattedData
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
Object.keys(datasets).forEach(key => {
|
|
74
|
+
newConfig.datasets[key].data = datasets[key]
|
|
75
|
+
})
|
|
76
|
+
return { newConfig, datasets }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const loadSingleDashboard = async config => {
|
|
80
|
+
let newConfig = { ...defaults, ...config } as DashboardConfig
|
|
81
|
+
|
|
82
|
+
if (config.datasets) {
|
|
83
|
+
return await loadData(newConfig)
|
|
84
|
+
} else {
|
|
85
|
+
const dataKey = newConfig.dataFileName || 'backwards-compatibility'
|
|
86
|
+
const data = await processDataLegacy(config)
|
|
87
|
+
|
|
88
|
+
const datasetsFull = {}
|
|
89
|
+
datasetsFull[dataKey] = {
|
|
90
|
+
data,
|
|
91
|
+
dataDescription: newConfig.dataDescription
|
|
92
|
+
}
|
|
93
|
+
newConfig.datasets = datasetsFull
|
|
94
|
+
|
|
95
|
+
getVizKeys(newConfig).forEach(vizKey => {
|
|
96
|
+
const newData = { dataKey, ..._.pick(newConfig, 'dataDescription', 'formattedData') }
|
|
97
|
+
newConfig.visualizations[vizKey] = { ...newConfig.visualizations[vizKey], ...newData }
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const blankFields = { data: [], dataUrl: '', dataFileName: '', dataFileSourceType: '', dataDescription: {}, formattedData: [] }
|
|
101
|
+
newConfig = { ...newConfig, ...blankFields }
|
|
102
|
+
|
|
103
|
+
if (newConfig.dashboard.filters) {
|
|
104
|
+
const dashboard = { ...newConfig.dashboard }
|
|
105
|
+
// replace filters with sharedFilters
|
|
106
|
+
if (!dashboard.sharedFilters) dashboard.sharedFilters = []
|
|
107
|
+
const filters = dashboard.filters.map(filter => {
|
|
108
|
+
return { ...filter, key: filter.label, showDropdown: true, usedBy: getVizKeys(newConfig) }
|
|
109
|
+
})
|
|
110
|
+
dashboard.sharedFilters = [...dashboard.sharedFilters, ...filters]
|
|
111
|
+
newConfig.dashboard = { ...dashboard, filters: undefined }
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const datasets: Record<string, Object[]> = { [dataKey]: data }
|
|
115
|
+
return { newConfig, datasets }
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const loadMultiDashboard = async (multiConfig: MultiDashboardConfig, selectedConfig: number) => {
|
|
120
|
+
const selectedDashboard = multiConfig.multiDashboards[selectedConfig]
|
|
121
|
+
let newConfig = { ...defaults, ...multiConfig, ...selectedDashboard, multiDashboards: multiConfig.multiDashboards, activeDashboard: selectedConfig } as MultiDashboardConfig
|
|
122
|
+
return await loadData(newConfig)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (!initial) return <Loading />
|
|
126
|
+
return <CdcDashboard isEditor={isEditor} isDebug={isDebug} initialState={initial} />
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export default MultiDashboardWrapper
|