@cdc/dashboard 4.25.3 → 4.25.5-1

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 (54) hide show
  1. package/Dynamic_Data.md +79 -0
  2. package/Override_Data.md +39 -0
  3. package/dist/cdcdashboard.js +67657 -70123
  4. package/examples/legend-issue-data.json +1874 -0
  5. package/examples/legend-issue.json +749 -0
  6. package/examples/map.json +628 -0
  7. package/index.html +1 -26
  8. package/package.json +10 -15
  9. package/src/CdcDashboardComponent.tsx +32 -5
  10. package/src/_stories/Dashboard.stories.tsx +2 -0
  11. package/src/_stories/_mock/api-filter-map.json +42 -1
  12. package/src/components/CollapsibleVisualizationRow.tsx +2 -2
  13. package/src/components/DashboardFilters/DashboardFilters.tsx +1 -1
  14. package/src/components/DashboardFilters/DashboardFiltersEditor/components/APIModal.tsx +129 -0
  15. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +680 -652
  16. package/src/components/DataDesignerModal.tsx +33 -14
  17. package/src/components/MultiConfigTabs/multiconfigtabs.styles.css +3 -0
  18. package/src/components/Row.tsx +2 -1
  19. package/src/components/VisualizationRow.tsx +1 -1
  20. package/src/helpers/reloadURLHelpers.ts +10 -2
  21. package/src/helpers/shouldLoadAllFilters.ts +30 -30
  22. package/src/index.tsx +2 -1
  23. package/src/scss/main.scss +0 -5
  24. package/src/store/dashboard.actions.ts +2 -0
  25. package/src/store/dashboard.reducer.ts +15 -0
  26. package/src/types/DataSet.ts +1 -0
  27. package/src/types/SharedFilter.ts +2 -0
  28. package/LICENSE +0 -201
  29. package/examples/private/DEV-10120.json +0 -1294
  30. package/examples/private/DEV-10527.json +0 -845
  31. package/examples/private/DEV-10586.json +0 -54319
  32. package/examples/private/DEV-10856.json +0 -54319
  33. package/examples/private/DEV-9199.json +0 -606
  34. package/examples/private/DEV-9644.json +0 -20092
  35. package/examples/private/DEV-9684.json +0 -2135
  36. package/examples/private/DEV-9932.json +0 -95
  37. package/examples/private/DEV-9989.json +0 -229
  38. package/examples/private/art-dashboard.json +0 -18174
  39. package/examples/private/art-scratch.json +0 -2406
  40. package/examples/private/bird-flu-2.json +0 -440
  41. package/examples/private/bird-flu.json +0 -413
  42. package/examples/private/dashboard-config-ehdi.json +0 -29915
  43. package/examples/private/dashboard-map-filter.json +0 -815
  44. package/examples/private/dashboard-margins.js +0 -15
  45. package/examples/private/dataset.json +0 -1452
  46. package/examples/private/dev-10856-2.json +0 -1348
  47. package/examples/private/ehdi-data.json +0 -29502
  48. package/examples/private/exposure-source-h5-data.csv +0 -26
  49. package/examples/private/fatal-data.csv +0 -3159
  50. package/examples/private/feelings.json +0 -1
  51. package/examples/private/gaza-issue.json +0 -1214
  52. package/examples/private/markup.json +0 -115
  53. package/examples/private/nhis.json +0 -1792
  54. package/examples/private/workforce.json +0 -2041
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdc/dashboard",
3
- "version": "4.25.3",
3
+ "version": "4.25.5-1",
4
4
  "description": "React component for combining multiple visualizations into a single dashboard",
5
5
  "moduleName": "CdcDashboard",
6
6
  "main": "dist/cdcdashboard",
@@ -27,27 +27,22 @@
27
27
  },
28
28
  "license": "Apache-2.0",
29
29
  "dependencies": {
30
- "@cdc/chart": "^4.25.3",
31
- "@cdc/core": "^4.25.3",
32
- "@cdc/data-bite": "^4.25.3",
33
- "@cdc/filtered-text": "^4.25.3",
34
- "@cdc/map": "^4.25.3",
35
- "@cdc/markup-include": "^4.25.3",
36
- "@cdc/waffle-chart": "^4.25.3",
37
- "html-react-parser": "^3.0.8",
30
+ "@cdc/chart": "^4.25.5-1",
31
+ "@cdc/core": "^4.25.5-1",
32
+ "@cdc/data-bite": "^4.25.5-1",
33
+ "@cdc/filtered-text": "^4.25.5-1",
34
+ "@cdc/map": "^4.25.5-1",
35
+ "@cdc/markup-include": "^4.25.5-1",
36
+ "@cdc/waffle-chart": "^4.25.5-1",
38
37
  "js-base64": "^2.5.2",
39
- "papaparse": "^5.3.0",
40
38
  "react-accessible-accordion": "^3.3.4",
41
39
  "react-dnd": "^14.0.2",
42
40
  "react-dnd-html5-backend": "^14.0.0",
43
- "react-table": "^7.5.0",
44
- "react-tooltip": "5.8.2-beta.3",
45
- "use-debounce": "^6.0.1",
46
- "whatwg-fetch": "^3.6.2"
41
+ "use-debounce": "^6.0.1"
47
42
  },
48
43
  "peerDependencies": {
49
44
  "react": "^18.2.0",
50
45
  "react-dom": "^18.2.0"
51
46
  },
52
- "gitHead": "b09566f5a7d57c8d0109e5f407257729d6b36846"
47
+ "gitHead": "1d0a6e716bc113e6bea3636fcae90ebf2d19bb5c"
53
48
  }
@@ -21,7 +21,7 @@ import getViewport from '@cdc/core/helpers/getViewport'
21
21
 
22
22
  import CdcChart from '@cdc/chart/src/CdcChartComponent'
23
23
  import CdcDataBite from '@cdc/data-bite/src/CdcDataBite'
24
- import CdcMap from '@cdc/map/src/CdcMap'
24
+ import CdcMap from '@cdc/map/src/CdcMapComponent'
25
25
  import CdcWaffleChart from '@cdc/waffle-chart/src/CdcWaffleChart'
26
26
  import CdcMarkupInclude from '@cdc/markup-include/src/CdcMarkupInclude'
27
27
  import CdcFilteredText from '@cdc/filtered-text/src/CdcFilteredText'
@@ -66,6 +66,7 @@ import { loadAPIFiltersFactory } from './helpers/loadAPIFilters'
66
66
  import Loader from '@cdc/core/components/Loader'
67
67
  import Alert from '@cdc/core/components/Alert'
68
68
  import { shouldLoadAllFilters } from './helpers/shouldLoadAllFilters'
69
+ import { subscribe, unsubscribe } from '@cdc/core/helpers/events'
69
70
 
70
71
  type DashboardProps = Omit<WCMSProps, 'configUrl'> & {
71
72
  initialState: InitialState
@@ -120,12 +121,16 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
120
121
  for (let i = 0; i < datasetKeys.length; i++) {
121
122
  const datasetKey = datasetKeys[i]
122
123
  const dataset = config.datasets[datasetKey]
123
-
124
- if (dataset.dataUrl && filters) {
124
+ const windowQueryParams = Object.fromEntries(new URLSearchParams(window.location.search))
125
+ const loadQueryParam = windowQueryParams[dataset.loadQueryParam || '']
126
+ if (dataset.dataUrl && (filters || loadQueryParam)) {
125
127
  const dataUrl = new URL(dataset.runtimeDataUrl || dataset.dataUrl, window.location.origin)
126
128
  const currentQSParams = Object.fromEntries(new URLSearchParams(dataUrl.search))
127
129
  const updatedQSParams = {}
128
- filters.forEach(filter => {
130
+ if (loadQueryParam) {
131
+ updatedQSParams[dataset.loadQueryParam] = loadQueryParam
132
+ }
133
+ filters?.forEach(filter => {
129
134
  if (
130
135
  filter.type === 'urlfilter' &&
131
136
  reloadURLHelpers.filterUsedByDataUrl(filter, datasetKey, config.visualizations, config.rows)
@@ -143,7 +148,6 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
143
148
  }
144
149
 
145
150
  if (!!filter.setByQueryParameter) {
146
- const windowQueryParams = Object.fromEntries(new URLSearchParams(window.location.search))
147
151
  const filterValue = windowQueryParams[filter.setByQueryParameter]
148
152
  const queryParam = filter.apiFilter?.valueSelector || filter.setByQueryParameter
149
153
  if (filterValue) {
@@ -271,6 +275,29 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
271
275
  dispatch({ type: 'SET_SHARED_FILTERS', payload: newConfig.dashboard.sharedFilters })
272
276
  }
273
277
 
278
+ const setEventData = ({ detail }) => {
279
+ try {
280
+ const newDatasets = Object.keys(detail).reduce((acc, key) => {
281
+ if (state.data[key] !== undefined) {
282
+ acc[key] = detail[key]
283
+ }
284
+ return acc
285
+ }, {})
286
+ const filteredData = { ...state.filteredData, ...newDatasets }
287
+ dispatch({ type: 'SET_FILTERED_DATA', payload: filteredData })
288
+ dispatch({ type: 'SET_DATA', payload: { ...state.data, ...newDatasets } })
289
+ } catch (e) {
290
+ console.error('Error setting event data: ', e)
291
+ }
292
+ }
293
+
294
+ useEffect(() => {
295
+ subscribe('cove_set_data', setEventData)
296
+ return () => {
297
+ unsubscribe('cove_set_data', setEventData)
298
+ }
299
+ }, [])
300
+
274
301
  useEffect(() => {
275
302
  const { config } = state
276
303
  const loadAllFilters = shouldLoadAllFilters(config, isEditor && !isPreview)
@@ -341,6 +341,8 @@ export const RegressionAPIFiltersMap: Story = {
341
341
  await sleep(1000)
342
342
  const topicsFilter = canvas.getByLabelText('Category', { selector: 'select' })
343
343
  await user.selectOptions(topicsFilter, ['topicId'])
344
+ await sleep(1000)
345
+
344
346
  const indicatorsFilter = canvas.getByLabelText('Indicator', { selector: 'select' })
345
347
  await user.selectOptions(indicatorsFilter, ['indicatorID'])
346
348
  const yearsFilter = canvas.getByLabelText('Year', { selector: 'select' })
@@ -113,6 +113,45 @@
113
113
  "hideGeoColumnInTooltip": false,
114
114
  "hidePrimaryColumnInTooltip": false
115
115
  },
116
+ "tooltips": {
117
+ "appearanceType": "hover",
118
+ "linkLabel": "Learn More",
119
+ "capitalizeLabels": true,
120
+ "opacity": 90
121
+ },
122
+ "map": {
123
+ "layers": [],
124
+ "patterns": []
125
+ },
126
+ "visual": {
127
+ "minBubbleSize": 1,
128
+ "maxBubbleSize": 20,
129
+ "extraBubbleBorder": false,
130
+ "cityStyle": "circle",
131
+ "cityStyleLabel": "",
132
+ "showBubbleZeros": false,
133
+ "additionalCityStyles": [],
134
+ "geoCodeCircleSize": 8
135
+ },
136
+ "hexMap": {
137
+ "type": "",
138
+ "shapeGroups": [
139
+ {
140
+ "legendTitle": "",
141
+ "legendDescription": "",
142
+ "items": [
143
+ {
144
+ "key": "",
145
+ "shape": "Arrow Up",
146
+ "column": "",
147
+ "operator": "=",
148
+ "value": ""
149
+ }
150
+ ]
151
+ }
152
+ ]
153
+ },
154
+ "annotations": [],
116
155
  "color": "greenBlue",
117
156
  "columns": {
118
157
  "geo": {
@@ -170,7 +209,8 @@
170
209
  "position": "side",
171
210
  "title": "Crude Prevalence",
172
211
  "separateZero": true
173
- }
212
+ },
213
+ "table": {}
174
214
  }
175
215
  },
176
216
  "type": "dashboard",
@@ -179,6 +219,7 @@
179
219
  "dataUrl": "http://test.gov/api/POC/TableData?DataValueTypeId=CRDMEDN"
180
220
  }
181
221
  },
222
+ "table": {},
182
223
  "filterBehavior": "Apply Button",
183
224
  "runtime": {},
184
225
  "uuid": 1684783370106
@@ -1,6 +1,6 @@
1
1
  import React, { useState, useEffect } from 'react'
2
2
  import Icon from '../../../core/components/ui/Icon'
3
- import { appFontSize } from '@cdc/core/helpers/cove/fontSettings'
3
+ import { APP_FONT_SIZE } from '@cdc/core/helpers/constants'
4
4
 
5
5
  type CollapsableVizRow = {
6
6
  allExpanded: boolean
@@ -17,7 +17,7 @@ const CollapsibleVisualizationRow: React.FC<CollapsableVizRow> = ({
17
17
  children
18
18
  }) => {
19
19
  const [isExpanded, setIsExpanded] = useState(allExpanded)
20
- const titleFontSize = ['xs', 'xxs'].includes(currentViewport) ? '13px' : `${appFontSize}px`
20
+ const titleFontSize = ['xs', 'xxs'].includes(currentViewport) ? '13px' : `${APP_FONT_SIZE}px`
21
21
 
22
22
  useEffect(() => {
23
23
  setIsExpanded(allExpanded)
@@ -8,7 +8,7 @@ import NestedDropdown from '@cdc/core/components/NestedDropdown'
8
8
  import { MouseEventHandler } from 'react'
9
9
  import Loader from '@cdc/core/components/Loader'
10
10
  import _ from 'lodash'
11
- import { DROPDOWN_STYLES } from '@cdc/core/components/Filters/Filters'
11
+ import { DROPDOWN_STYLES } from '@cdc/core/components/Filters/components/Dropdown'
12
12
 
13
13
  type DashboardFilterProps = {
14
14
  show: number[]
@@ -0,0 +1,129 @@
1
+ import { useState } from 'react'
2
+ import { SharedFilter } from '../../../../types/SharedFilter'
3
+ import Tooltip from '@cdc/core/components/ui/Tooltip'
4
+ import Icon from '@cdc/core/components/ui/Icon'
5
+
6
+ type APIModalProps = {
7
+ filter: SharedFilter
8
+ isNestedDropdown: boolean
9
+ updateAPIFilter: Function
10
+ }
11
+
12
+ const APIModal: React.FC<APIModalProps> = ({ filter, isNestedDropdown, updateAPIFilter }) => {
13
+ const [APIEndpoint, setAPIEndpoint] = useState(filter.apiFilter?.apiEndpoint || '')
14
+ const [APIValueSelector, setAPIValueSelector] = useState(filter.apiFilter?.valueSelector || '')
15
+ const [APITextSelector, setAPITextSelector] = useState(filter.apiFilter?.textSelector || '')
16
+ const [APISubGroupValueSelector, setAPISubGroupValueSelector] = useState(filter.apiFilter?.subgroupValueSelector)
17
+ const [APISubGroupTextSelector, setAPISubGroupTextSelector] = useState(filter.apiFilter?.subgroupTextSelector)
18
+ return (
19
+ <fieldset className='mb-1 px-3 cdc-open-viz-module'>
20
+ <label className='d-block'>
21
+ <span>API Endpoint: </span>
22
+ <textarea
23
+ value={APIEndpoint}
24
+ rows={4}
25
+ onChange={e => setAPIEndpoint(e.target.value)}
26
+ className='w-100'
27
+ style={{ minHeight: '1.5rem', maxWidth: '90%' }}
28
+ />
29
+ {isNestedDropdown && (
30
+ <Tooltip style={{ textTransform: 'none' }}>
31
+ <Tooltip.Target>
32
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
33
+ </Tooltip.Target>
34
+ <Tooltip.Content>
35
+ <p>Your API Endpoint should return both value selector values.</p>
36
+ </Tooltip.Content>
37
+ </Tooltip>
38
+ )}
39
+ </label>
40
+ <div className='d-flex'>
41
+ <div className={`w-50${isNestedDropdown ? ' border border-dark p-1 m-1' : ''}`}>
42
+ <label>
43
+ <span>Value Selector: </span>
44
+ <input type='text' value={APIValueSelector || ''} onChange={e => setAPIValueSelector(e.target.value)} />
45
+ <Tooltip style={{ textTransform: 'none' }}>
46
+ <Tooltip.Target>
47
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
48
+ </Tooltip.Target>
49
+ <Tooltip.Content>
50
+ <p>Value to use in the html option element</p>
51
+ </Tooltip.Content>
52
+ </Tooltip>
53
+ <p>{` * Required`}</p>
54
+ </label>
55
+ <label>
56
+ <span>Display Text Selector: </span>
57
+ <input type='text' value={APITextSelector || ''} onChange={e => setAPITextSelector(e.target.value)} />
58
+ <Tooltip style={{ textTransform: 'none' }}>
59
+ <Tooltip.Target>
60
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
61
+ </Tooltip.Target>
62
+ <Tooltip.Content>
63
+ <p>Text to use in the html option element. If none is applied value selector will be used.</p>
64
+ </Tooltip.Content>
65
+ </Tooltip>
66
+ <p>{` * Optional`}</p>
67
+ </label>
68
+ </div>
69
+
70
+ {isNestedDropdown && (
71
+ <div className={`w-50${isNestedDropdown ? ' border border-dark p-1 m-1' : ''}`}>
72
+ <label>
73
+ <span>Subgroup Value Selector: </span>
74
+ <input
75
+ type='text'
76
+ value={APISubGroupValueSelector || ''}
77
+ onChange={e => setAPISubGroupValueSelector(e.target.value)}
78
+ />
79
+ <Tooltip style={{ textTransform: 'none' }}>
80
+ <Tooltip.Target>
81
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
82
+ </Tooltip.Target>
83
+ <Tooltip.Content>
84
+ <p>Value to use in the html option element</p>
85
+ </Tooltip.Content>
86
+ </Tooltip>
87
+ <p>{` * Required`}</p>
88
+ </label>
89
+ <label>
90
+ <span>Subgroup Display Text Selector: </span>
91
+ <input
92
+ type='text'
93
+ value={APISubGroupTextSelector || ''}
94
+ onChange={e => setAPISubGroupTextSelector(e.target.value)}
95
+ />
96
+ <Tooltip style={{ textTransform: 'none' }}>
97
+ <Tooltip.Target>
98
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
99
+ </Tooltip.Target>
100
+ <Tooltip.Content>
101
+ <p>Text to use in the html option element. If none is applied value selector will be used.</p>
102
+ </Tooltip.Content>
103
+ </Tooltip>
104
+ <p>{` * Optional`}</p>
105
+ </label>
106
+ </div>
107
+ )}
108
+ </div>
109
+ <div className='d-flex justify-content-end mt-2'>
110
+ <button
111
+ className='btn btn-primary mt-2'
112
+ onClick={() =>
113
+ updateAPIFilter(
114
+ APIEndpoint,
115
+ APIValueSelector,
116
+ APITextSelector,
117
+ APISubGroupValueSelector,
118
+ APISubGroupTextSelector
119
+ )
120
+ }
121
+ >
122
+ Save
123
+ </button>
124
+ </div>
125
+ </fieldset>
126
+ )
127
+ }
128
+
129
+ export default APIModal