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