@cdc/dashboard 4.24.12 → 4.25.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 (38) hide show
  1. package/dist/cdcdashboard.js +68752 -67417
  2. package/examples/private/DEV-10120.json +1294 -0
  3. package/examples/private/DEV-9989.json +229 -0
  4. package/examples/private/art-dashboard.json +2 -2
  5. package/examples/private/bird-flu-2.json +440 -0
  6. package/examples/private/bird-flu.json +413 -0
  7. package/examples/private/dashboard-config-ehdi.json +29915 -0
  8. package/examples/private/dashboard-margins.js +15 -0
  9. package/examples/private/dataset.json +1452 -0
  10. package/examples/private/ehdi-data.json +29502 -0
  11. package/examples/private/exposure-source-h5-data.csv +26 -0
  12. package/examples/private/workforce.json +2041 -0
  13. package/index.html +2 -6
  14. package/package.json +9 -9
  15. package/src/CdcDashboardComponent.tsx +12 -4
  16. package/src/_stories/Dashboard.stories.tsx +32 -0
  17. package/src/_stories/_mock/data-bite-dash-test.json +1 -0
  18. package/src/_stories/_mock/data-bite-dash-test_1.json +1 -0
  19. package/src/_stories/_mock/data-bite-dash-test_1_1.json +1 -0
  20. package/src/_stories/_mock/data-bite-dash-test_1_1_1.json +1 -0
  21. package/src/components/CollapsibleVisualizationRow.tsx +2 -2
  22. package/src/components/Column.tsx +12 -1
  23. package/src/components/DashboardFilters/DashboardFilters.tsx +4 -4
  24. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +1 -3
  25. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +1 -1
  26. package/src/components/DashboardFilters/dashboardfilter.styles.css +2 -0
  27. package/src/components/ExpandCollapseButtons.tsx +1 -1
  28. package/src/components/Header/Header.tsx +1 -2
  29. package/src/components/MultiConfigTabs/MultiConfigTabs.tsx +2 -2
  30. package/src/components/MultiConfigTabs/MultiTabs.tsx +1 -1
  31. package/src/components/VisualizationRow.tsx +2 -2
  32. package/src/components/Widget.tsx +9 -3
  33. package/src/helpers/apiFilterHelpers.ts +1 -1
  34. package/src/index.tsx +1 -0
  35. package/src/scss/main.scss +1 -12
  36. package/src/store/dashboard.actions.ts +2 -2
  37. package/src/store/dashboard.reducer.ts +17 -8
  38. package/src/types/DashboardConfig.ts +2 -0
package/index.html CHANGED
@@ -17,11 +17,7 @@
17
17
  }
18
18
  </style>
19
19
  <link rel="stylesheet prefetch" href="examples/custom/css/respiratory.css" />
20
- <link
21
- rel="stylesheet prefetch"
22
- href="https://www.cdc.gov/TemplatePackage/contrib/libs/bootstrap/latest/css/bootstrap.min.css?_=39423"
23
- />
24
- <link rel="stylesheet prefetch" href="https://www.cdc.gov/TemplatePackage/4.0/assets/css/app.min.css?_=39423" />
20
+ <link rel="stylesheet prefetch" href="https://www.cdc.gov/TemplatePackage/5.0/css/app.min.css?_=71669" />
25
21
  </head>
26
22
 
27
23
  <body>
@@ -34,7 +30,7 @@
34
30
  <!-- <div class="react-container" data-config="/examples/dev-8332.json"></div> -->
35
31
  <!-- <div class="react-container" data-config="/examples/dashboard-gallery.json"></div> -->
36
32
  <!-- <div class="react-container" data-config="/examples/filtered-dash.json"></div> -->
37
- <div class="react-container" data-config="/examples/all-components.json"></div>
33
+ <div class="react-container" data-config="/examples/private/art-dashboard.json"></div>
38
34
  <!-- <div class="react-container" data-config="/examples/sankey.json"></div> -->
39
35
  <!-- <div class="react-container" data-config="/examples/DEV-6574.json"></div> -->
40
36
  <!-- <div class="react-container" data-config="/examples/default-multi-dataset-2.json"></div> -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdc/dashboard",
3
- "version": "4.24.12",
3
+ "version": "4.25.1",
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.12",
31
- "@cdc/core": "^4.24.12",
32
- "@cdc/data-bite": "^4.24.12",
33
- "@cdc/filtered-text": "^4.24.12",
34
- "@cdc/map": "^4.24.12",
35
- "@cdc/markup-include": "^4.24.12",
36
- "@cdc/waffle-chart": "^4.24.12",
30
+ "@cdc/chart": "^4.25.1",
31
+ "@cdc/core": "^4.25.1",
32
+ "@cdc/data-bite": "^4.25.1",
33
+ "@cdc/filtered-text": "^4.25.1",
34
+ "@cdc/map": "^4.25.1",
35
+ "@cdc/markup-include": "^4.25.1",
36
+ "@cdc/waffle-chart": "^4.25.1",
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": "347414f1da4b0e9bf2f22a7b59335deccf0b2d9c"
52
+ "gitHead": "c32d727f516fe3525178e3a6480abbe70b2a20d6"
53
53
  }
@@ -19,7 +19,7 @@ import Loading from '@cdc/core/components/Loading'
19
19
  import { DataTransform } from '@cdc/core/helpers/DataTransform'
20
20
  import getViewport from '@cdc/core/helpers/getViewport'
21
21
 
22
- import CdcChart from '@cdc/chart/src/CdcChart'
22
+ import CdcChart from '@cdc/chart/src/CdcChartComponent'
23
23
  import CdcDataBite from '@cdc/data-bite/src/CdcDataBite'
24
24
  import CdcMap from '@cdc/map/src/CdcMap'
25
25
  import CdcWaffleChart from '@cdc/waffle-chart/src/CdcWaffleChart'
@@ -228,7 +228,15 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
228
228
  )
229
229
  dispatch({ type: 'SET_FILTERED_DATA', payload: filteredData })
230
230
  const visualizations = reloadURLHelpers.getVisualizationsWithFormattedData(config.visualizations, newData)
231
- dispatch({ type: 'SET_CONFIG', payload: { dashboard: dashboardConfig, datasets: newDatasets, visualizations } })
231
+ dispatch({
232
+ type: 'SET_CONFIG',
233
+ payload: {
234
+ dashboard: dashboardConfig,
235
+ datasets: newDatasets,
236
+ visualizations,
237
+ activeDashboard: config.activeDashboard
238
+ }
239
+ })
232
240
  setAPILoading(false)
233
241
  }
234
242
  }
@@ -268,7 +276,7 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
268
276
  const loadAllFilters = shouldLoadAllFilters(config, isEditor && !isPreview)
269
277
  const sharedFiltersWithValues = addValuesToDashboardFilters(config.dashboard.sharedFilters, state.data)
270
278
 
271
- loadAPIFilters(sharedFiltersWithValues, apiFilterDropdowns, loadAllFilters).then(newFilters => {
279
+ loadAPIFilters(sharedFiltersWithValues, apiFilterDropdowns, loadAllFilters)?.then(newFilters => {
272
280
  const allValuesSelected = newFilters.every(filter => {
273
281
  return filter.type === 'datafilter' || filter.active
274
282
  })
@@ -534,7 +542,7 @@ export default function CdcDashboard({ initialState, isEditor = false, isDebug =
534
542
  classes={[`dashboard-title`, `${config.dashboard.theme ?? 'theme-blue'}`]}
535
543
  />
536
544
  {/* Description */}
537
- {description && <div className='subtext'>{parse(description)}</div>}
545
+ {description && <div className='subtext mb-3'>{parse(description)}</div>}
538
546
  {/* Visualizations */}
539
547
  {config.rows &&
540
548
  config.rows
@@ -24,6 +24,10 @@ import { ConfigRow } from '../types/ConfigRow'
24
24
  import BumpChartConfig from './_mock/bump-chart.json'
25
25
  import MethodologyConfig from './_mock/methodology.json'
26
26
  import methodologyAPI from './_mock/methodologyAPI'
27
+ import TopSpacing_1 from './_mock/data-bite-dash-test.json'
28
+ import TopSpacing_2 from './_mock/data-bite-dash-test_1.json'
29
+ import TopSpacing_3 from './_mock/data-bite-dash-test_1_1.json'
30
+ import TopSpacing_4 from './_mock/data-bite-dash-test_1_1_1.json'
27
31
 
28
32
  const meta: Meta<typeof Dashboard> = {
29
33
  title: 'Components/Pages/Dashboard',
@@ -403,4 +407,32 @@ export const RegressionMultiVisualization: Story = {
403
407
  }
404
408
  }
405
409
 
410
+ export const Top_Spacing_1: Story = {
411
+ args: {
412
+ config: TopSpacing_1,
413
+ isEditor: false
414
+ }
415
+ }
416
+
417
+ export const Top_Spacing_2: Story = {
418
+ args: {
419
+ config: TopSpacing_2,
420
+ isEditor: false
421
+ }
422
+ }
423
+
424
+ export const Top_Spacing_3: Story = {
425
+ args: {
426
+ config: TopSpacing_3,
427
+ isEditor: false
428
+ }
429
+ }
430
+
431
+ export const Top_Spacing_4: Story = {
432
+ args: {
433
+ config: TopSpacing_4,
434
+ isEditor: false
435
+ }
436
+ }
437
+
406
438
  export default meta
@@ -0,0 +1 @@
1
+ {"dashboard":{"theme":"theme-blue","sharedFilters":[],"description":"Dash Description","title":"Dashboard Name"},"rows":[{"columns":[{"width":6,"widget":"data-bite1722537849962"},{"width":6,"widget":"data-bite1728059122204"}],"dataDescription":{"horizontal":false,"series":true,"singleRow":true},"dataKey":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"}],"visualizations":{"data-bite1722537849962":{"type":"data-bite","dataBite":"","dataFunction":"Sum","dataColumn":"specimens tested","bitePosition":"Left","biteFontSize":24,"fontSize":"medium","biteBody":"specimens tested that would have detected influenza A(H5) or other novel influenza viruses","imageData":{"display":"none","url":"","alt":"","options":[]},"dataFormat":{"roundToPlace":0,"commas":true,"prefix":"","suffix":"+"},"biteStyle":"title","filters":[],"subtext":"","title":"Specimens tested","theme":"theme-blue","shadow":false,"visual":{"border":false,"accent":false,"background":false,"hideBackgroundColor":false,"borderColorTheme":false},"general":{"isCompactStyle":false},"filterBehavior":"Filter Change","openModal":true,"uid":"data-bite1722537849962","visualizationType":"data-bite","dataDescription":{"horizontal":false,"series":true,"singleRow":true},"version":"4.24.10","dataKey":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"},"data-bite1728059122204":{"type":"data-bite","dataBite":"","dataFunction":"Sum","dataColumn":"Human cases","bitePosition":"Left","biteFontSize":24,"fontSize":"medium","biteBody":"case detected through national flu surveillance","imageData":{"display":"none","url":"","alt":"","options":[]},"dataFormat":{"roundToPlace":0,"commas":true,"prefix":"","suffix":""},"biteStyle":"title","filters":[],"subtext":"","title":"Human cases","theme":"theme-blue","shadow":false,"visual":{"border":false,"accent":false,"background":false,"hideBackgroundColor":false,"borderColorTheme":false},"general":{"isCompactStyle":false},"filterBehavior":"Filter Change","openModal":true,"uid":"data-bite1728059122204","visualizationType":"data-bite","dataDescription":{"horizontal":false,"series":true,"singleRow":true},"version":"4.24.10","dataKey":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"}},"table":{"label":"Data Table","show":false,"showDownloadUrl":false,"showVertical":true},"datasets":{"/bird-flu/modules/situation-summary/national-flu-surveillance.csv":{"dataFileSize":39,"dataFileName":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv","dataFileSourceType":"url","dataFileFormat":"OCTET-STREAM","preview":true,"dataUrl":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"}},"type":"dashboard","version":"4.24.10","uuid":1722537847428}
@@ -0,0 +1 @@
1
+ {"dashboard":{"theme":"theme-blue","sharedFilters":[],"description":"Dash Description","title":""},"rows":[{"columns":[{"width":6,"widget":"data-bite1722537849962"},{"width":6,"widget":"data-bite1728059122204"}],"dataDescription":{"horizontal":false,"series":true,"singleRow":true},"dataKey":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"}],"visualizations":{"data-bite1722537849962":{"type":"data-bite","dataBite":"","dataFunction":"Sum","dataColumn":"specimens tested","bitePosition":"Left","biteFontSize":24,"fontSize":"medium","biteBody":"specimens tested that would have detected influenza A(H5) or other novel influenza viruses","imageData":{"display":"none","url":"","alt":"","options":[]},"dataFormat":{"roundToPlace":0,"commas":true,"prefix":"","suffix":"+"},"biteStyle":"title","filters":[],"subtext":"","title":"Specimens tested","theme":"theme-blue","shadow":false,"visual":{"border":false,"accent":false,"background":false,"hideBackgroundColor":false,"borderColorTheme":false},"general":{"isCompactStyle":false},"filterBehavior":"Filter Change","openModal":true,"uid":"data-bite1722537849962","visualizationType":"data-bite","dataDescription":{"horizontal":false,"series":true,"singleRow":true},"version":"4.24.10","dataKey":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"},"data-bite1728059122204":{"type":"data-bite","dataBite":"","dataFunction":"Sum","dataColumn":"Human cases","bitePosition":"Left","biteFontSize":24,"fontSize":"medium","biteBody":"case detected through national flu surveillance","imageData":{"display":"none","url":"","alt":"","options":[]},"dataFormat":{"roundToPlace":0,"commas":true,"prefix":"","suffix":""},"biteStyle":"title","filters":[],"subtext":"","title":"Human cases","theme":"theme-blue","shadow":false,"visual":{"border":false,"accent":false,"background":false,"hideBackgroundColor":false,"borderColorTheme":false},"general":{"isCompactStyle":false},"filterBehavior":"Filter Change","openModal":true,"uid":"data-bite1728059122204","visualizationType":"data-bite","dataDescription":{"horizontal":false,"series":true,"singleRow":true},"version":"4.24.10","dataKey":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"}},"table":{"label":"Data Table","show":false,"showDownloadUrl":false,"showVertical":true},"datasets":{"/bird-flu/modules/situation-summary/national-flu-surveillance.csv":{"dataFileSize":39,"dataFileName":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv","dataFileSourceType":"url","dataFileFormat":"OCTET-STREAM","preview":true,"dataUrl":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"}},"type":"dashboard","version":"4.24.10","uuid":1722537847428}
@@ -0,0 +1 @@
1
+ {"dashboard":{"theme":"theme-blue","sharedFilters":[],"description":"","title":"Title no description"},"rows":[{"columns":[{"width":6,"widget":"data-bite1722537849962"},{"width":6,"widget":"data-bite1728059122204"}],"dataDescription":{"horizontal":false,"series":true,"singleRow":true},"dataKey":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"}],"visualizations":{"data-bite1722537849962":{"type":"data-bite","dataBite":"","dataFunction":"Sum","dataColumn":"specimens tested","bitePosition":"Left","biteFontSize":24,"fontSize":"medium","biteBody":"specimens tested that would have detected influenza A(H5) or other novel influenza viruses","imageData":{"display":"none","url":"","alt":"","options":[]},"dataFormat":{"roundToPlace":0,"commas":true,"prefix":"","suffix":"+"},"biteStyle":"title","filters":[],"subtext":"","title":"Specimens tested","theme":"theme-blue","shadow":false,"visual":{"border":false,"accent":false,"background":false,"hideBackgroundColor":false,"borderColorTheme":false},"general":{"isCompactStyle":false},"filterBehavior":"Filter Change","openModal":true,"uid":"data-bite1722537849962","visualizationType":"data-bite","dataDescription":{"horizontal":false,"series":true,"singleRow":true},"version":"4.24.10","dataKey":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"},"data-bite1728059122204":{"type":"data-bite","dataBite":"","dataFunction":"Sum","dataColumn":"Human cases","bitePosition":"Left","biteFontSize":24,"fontSize":"medium","biteBody":"case detected through national flu surveillance","imageData":{"display":"none","url":"","alt":"","options":[]},"dataFormat":{"roundToPlace":0,"commas":true,"prefix":"","suffix":""},"biteStyle":"title","filters":[],"subtext":"","title":"Human cases","theme":"theme-blue","shadow":false,"visual":{"border":false,"accent":false,"background":false,"hideBackgroundColor":false,"borderColorTheme":false},"general":{"isCompactStyle":false},"filterBehavior":"Filter Change","openModal":true,"uid":"data-bite1728059122204","visualizationType":"data-bite","dataDescription":{"horizontal":false,"series":true,"singleRow":true},"version":"4.24.10","dataKey":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"}},"table":{"label":"Data Table","show":false,"showDownloadUrl":false,"showVertical":true},"datasets":{"/bird-flu/modules/situation-summary/national-flu-surveillance.csv":{"dataFileSize":39,"dataFileName":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv","dataFileSourceType":"url","dataFileFormat":"OCTET-STREAM","preview":true,"dataUrl":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"}},"type":"dashboard","version":"4.24.10","uuid":1722537847428}
@@ -0,0 +1 @@
1
+ {"dashboard":{"theme":"theme-blue","sharedFilters":[],"description":"","title":""},"rows":[{"columns":[{"width":6,"widget":"data-bite1722537849962"},{"width":6,"widget":"data-bite1728059122204"}],"dataDescription":{"horizontal":false,"series":true,"singleRow":true},"dataKey":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"}],"visualizations":{"data-bite1722537849962":{"type":"data-bite","dataBite":"","dataFunction":"Sum","dataColumn":"specimens tested","bitePosition":"Left","biteFontSize":24,"fontSize":"medium","biteBody":"specimens tested that would have detected influenza A(H5) or other novel influenza viruses","imageData":{"display":"none","url":"","alt":"","options":[]},"dataFormat":{"roundToPlace":0,"commas":true,"prefix":"","suffix":"+"},"biteStyle":"title","filters":[],"subtext":"","title":"Specimens tested","theme":"theme-blue","shadow":false,"visual":{"border":false,"accent":false,"background":false,"hideBackgroundColor":false,"borderColorTheme":false},"general":{"isCompactStyle":false},"filterBehavior":"Filter Change","openModal":true,"uid":"data-bite1722537849962","visualizationType":"data-bite","dataDescription":{"horizontal":false,"series":true,"singleRow":true},"version":"4.24.10","dataKey":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"},"data-bite1728059122204":{"type":"data-bite","dataBite":"","dataFunction":"Sum","dataColumn":"Human cases","bitePosition":"Left","biteFontSize":24,"fontSize":"medium","biteBody":"case detected through national flu surveillance","imageData":{"display":"none","url":"","alt":"","options":[]},"dataFormat":{"roundToPlace":0,"commas":true,"prefix":"","suffix":""},"biteStyle":"title","filters":[],"subtext":"","title":"Human cases","theme":"theme-blue","shadow":false,"visual":{"border":false,"accent":false,"background":false,"hideBackgroundColor":false,"borderColorTheme":false},"general":{"isCompactStyle":false},"filterBehavior":"Filter Change","openModal":true,"uid":"data-bite1728059122204","visualizationType":"data-bite","dataDescription":{"horizontal":false,"series":true,"singleRow":true},"version":"4.24.10","dataKey":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"}},"table":{"label":"Data Table","show":false,"showDownloadUrl":false,"showVertical":true},"datasets":{"/bird-flu/modules/situation-summary/national-flu-surveillance.csv":{"dataFileSize":39,"dataFileName":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv","dataFileSourceType":"url","dataFileFormat":"OCTET-STREAM","preview":true,"dataUrl":"/bird-flu/modules/situation-summary/national-flu-surveillance.csv"}},"type":"dashboard","version":"4.24.10","uuid":1722537847428}
@@ -1,5 +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
4
 
4
5
  type CollapsableVizRow = {
5
6
  allExpanded: boolean
@@ -16,8 +17,7 @@ const CollapsibleVisualizationRow: React.FC<CollapsableVizRow> = ({
16
17
  children
17
18
  }) => {
18
19
  const [isExpanded, setIsExpanded] = useState(allExpanded)
19
- const fontSizes = { small: 16, medium: 18, large: 20 }
20
- const titleFontSize = ['xs', 'xxs'].includes(currentViewport) ? '13px' : `${fontSizes[fontSize]}px`
20
+ const titleFontSize = ['xs', 'xxs'].includes(currentViewport) ? '13px' : `${appFontSize}px`
21
21
 
22
22
  useEffect(() => {
23
23
  setIsExpanded(allExpanded)
@@ -37,10 +37,21 @@ const Column = ({ data, rowIdx, colIdx }) => {
37
37
  classNames.push('column--populated')
38
38
  }
39
39
 
40
+ const handleTitle = config => {
41
+ if (!config) return
42
+ if (config.type === 'map') return config.general.title
43
+ if (config.type === 'markup-include') return config.contentEditor?.title
44
+ return config.title
45
+ }
46
+
40
47
  return (
41
48
  <div className={classNames.join(' ')} ref={drop}>
42
49
  {widget ? (
43
- <Widget widgetConfig={{ rowIdx, colIdx, ...widget }} type={widget.visualizationType ?? widget.general?.geoType} />
50
+ <Widget
51
+ title={handleTitle(widget)}
52
+ widgetConfig={{ rowIdx, colIdx, ...widget }}
53
+ type={widget.visualizationType ?? widget.general?.geoType}
54
+ />
44
55
  ) : (
45
56
  <p className='builder-column__text'>
46
57
  Drag and drop <br /> visualization
@@ -122,12 +122,12 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
122
122
  )
123
123
  }
124
124
 
125
- const formGroupClass = `form-group mr-3 mb-1${loading ? ' loading-filter' : ''}`
125
+ const formGroupClass = `form-group me-4 mb-1${loading ? ' loading-filter' : ''}`
126
126
 
127
127
  return (
128
128
  <div className={formGroupClass} key={`${label}-filtersection-${filterIndex}`}>
129
129
  {label && (
130
- <label className='font-weight-bold mt-1 mb-0' htmlFor={`filter-${filterIndex}`}>
130
+ <label className='font-weight-bold mb-2' htmlFor={`filter-${filterIndex}`}>
131
131
  {label}
132
132
  </label>
133
133
  )}
@@ -143,8 +143,8 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
143
143
  />
144
144
  ) : filter.filterStyle === FILTER_STYLE.nestedDropdown ? (
145
145
  <NestedDropdown
146
- activeGroup={filter.active as string}
147
- activeSubGroup={_key ? filter.subGrouping?.active : activeSubGroupValue}
146
+ activeGroup={(filter.queuedActive?.[0] || filter.active) as string}
147
+ activeSubGroup={_key ? filter.queuedActive?.[1] || filter.subGrouping?.active : activeSubGroupValue}
148
148
  filterIndex={filterIndex}
149
149
  options={_key ? getNestedDropdownOptions(apiFilterDropdowns[_key]) : nestedOptions}
150
150
  listLabel={label}
@@ -40,7 +40,7 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
40
40
  Number
41
41
  )
42
42
  return config.dashboard.sharedFilters
43
- .map<[number, string]>(({ key }, i) => [i, key])
43
+ ?.map<[number, string]>(({ key }, i) => [i, key])
44
44
  .filter(([filterIndex]) => !sharedFilterIndexes.includes(filterIndex)) // filter out already added filters
45
45
  .map(([filterIndex, filterName]) => (
46
46
  <option key={filterIndex} value={filterIndex}>{`${filterIndex} - ${filterName}`}</option>
@@ -274,9 +274,7 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
274
274
  </select>
275
275
  </label>
276
276
  ) : (
277
-
278
277
  <button onClick={() => setCanAddExisting(true)} className='btn btn-primary full-width mt-2'>
279
-
280
278
  Add Existing Dashboard Filter
281
279
  </button>
282
280
  )}
@@ -226,7 +226,7 @@ const FilterEditor: React.FC<FilterEditorProps> = ({ filter, config, updateFilte
226
226
  </label>
227
227
  {filter.filterStyle === FILTER_STYLE.dropdown && (
228
228
  <label>
229
- <span className='mr-1'>Show Dropdown</span>
229
+ <span className='me-1'>Show Dropdown</span>
230
230
  <input
231
231
  type='checkbox'
232
232
  checked={filter.showDropdown}
@@ -2,6 +2,8 @@
2
2
  :is(label) {
3
3
  margin-bottom: 0;
4
4
  margin-top: 0.5rem;
5
+ font-size: var(--filter-label-font-size);
6
+ font-weight: 700;
5
7
  }
6
8
  .btn {
7
9
  /* this is the height that is defined for the .form-control class in _forms.scss in bootstrap. */
@@ -9,7 +9,7 @@ const ExpandCollapseButtons: React.FC<ExpandCollapseButtonsProps> = ({ setAllExp
9
9
  <button className='btn expand-collapse-buttons' onClick={() => setAllExpanded(false)}>
10
10
  - Collapse All
11
11
  </button>
12
- <button className='btn expand-collapse-buttons mr-2' onClick={() => setAllExpanded(true)}>
12
+ <button className='btn expand-collapse-buttons me-2' onClick={() => setAllExpanded(true)}>
13
13
  + Expand All
14
14
  </button>
15
15
  </div>
@@ -6,7 +6,6 @@ import './index.scss'
6
6
  import MultiConfigTabs from '../MultiConfigTabs'
7
7
  import { Tab } from '../../types/Tab'
8
8
  import _ from 'lodash'
9
- import { getVizRowColumnLocator } from '../../helpers/getVizRowColumnLocator'
10
9
 
11
10
  type HeaderProps = {
12
11
  back?: any
@@ -29,7 +28,7 @@ const Header = (props: HeaderProps) => {
29
28
  // the Widget component will do a data fetch if no data is available for the visualization
30
29
  // this is intended to help visualization developers.
31
30
  type SampleData = Record<string, { sample: boolean }> & Object[]
32
- if (Object.values(data).some((d: SampleData) => d.sample)) {
31
+ if (Object.values(data).some((d: SampleData) => d?.sample)) {
33
32
  const sampleDataRemoved = Object.keys(data).reduce((acc, key) => {
34
33
  if ((data[key] as SampleData).sample) {
35
34
  acc[key] = []
@@ -86,7 +86,7 @@ const Tab = ({ name, handleClick, tabs, index, active }) => {
86
86
  ) : (
87
87
  <>
88
88
  {name}
89
- <button className='btn btn-danger border-0 ml-1' onClick={handleRemove}>
89
+ <button className='btn btn-danger border-0 ms-1' onClick={handleRemove}>
90
90
  X
91
91
  </button>
92
92
  </>
@@ -117,7 +117,7 @@ const MultiConfigTabs = () => {
117
117
 
118
118
  if (!config.multiDashboards) return null
119
119
  return (
120
- <ul className='nav nav-tabs multi-config-tabs'>
120
+ <ul className='nav nav-tabs multi-config-tabs mb-4'>
121
121
  {tabs.map((tab, index) => (
122
122
  <Tab
123
123
  key={tab + index}
@@ -21,7 +21,7 @@ const MultiTabs = () => {
21
21
 
22
22
  if (!config.multiDashboards) return null
23
23
  return (
24
- <ul className='nav nav-tabs multi-config-tabs'>
24
+ <ul className='nav nav-tabs multi-config-tabs mb-4'>
25
25
  {tabs.map((tab, index) => (
26
26
  <li key={tab + index} className='nav-item'>
27
27
  <a
@@ -3,7 +3,6 @@ import React, { useContext, useMemo } from 'react'
3
3
  import Toggle from './Toggle'
4
4
  import _ from 'lodash'
5
5
  import { ConfigRow } from '../types/ConfigRow'
6
- import CdcChart from '@cdc/chart/src/CdcChart'
7
6
  import CdcDataBite from '@cdc/data-bite/src/CdcDataBite'
8
7
  import CdcMap from '@cdc/map/src/CdcMap'
9
8
  import CdcWaffleChart from '@cdc/waffle-chart/src/CdcWaffleChart'
@@ -18,6 +17,7 @@ import FootnotesStandAlone from '@cdc/core/components/Footnotes/FootnotesStandAl
18
17
  import CollapsibleVisualizationRow from './CollapsibleVisualizationRow'
19
18
  import { DashboardFilters } from '../types/DashboardFilters'
20
19
  import { hasDashboardApplyBehavior } from '../helpers/hasDashboardApplyBehavior'
20
+ import CdcChart from '@cdc/chart/src/CdcChartComponent'
21
21
 
22
22
  type VisualizationWrapperProps = {
23
23
  allExpanded: boolean
@@ -160,7 +160,7 @@ const VisualizationRow: React.FC<VizRowProps> = ({
160
160
  <div
161
161
  key={`vis__${index}__${colIndex}`}
162
162
  className={`col-12 col-md-${col.width}${!shouldShow ? ' d-none' : ''}${
163
- hideVisualization ? ' hide-parent-visualization' : ' mt-5 p-1'
163
+ hideVisualization ? ' hide-parent-visualization' : ' mb-4'
164
164
  }`}
165
165
  >
166
166
  {row.toggle && !hideVisualization && (
@@ -33,12 +33,13 @@ const labelHash = {
33
33
 
34
34
  type WidgetConfig = AnyVisualization & { rowIdx: number; colIdx: number }
35
35
  type WidgetProps = {
36
+ title: string
36
37
  widgetConfig?: WidgetConfig
37
38
  addVisualization?: Function
38
39
  type: string
39
40
  }
40
41
 
41
- const Widget = ({ widgetConfig, addVisualization, type }: WidgetProps) => {
42
+ const Widget = ({ title, widgetConfig, addVisualization, type }: WidgetProps) => {
42
43
  const { overlay } = useGlobalContext()
43
44
  const { config, data } = useContext(DashboardContext)
44
45
  const dispatch = useContext(DashboardDispatchContext)
@@ -74,9 +75,10 @@ const Widget = ({ widgetConfig, addVisualization, type }: WidgetProps) => {
74
75
 
75
76
  const deleteWidget = () => {
76
77
  if (!widgetConfig) return
78
+
77
79
  dispatch({
78
80
  type: 'DELETE_WIDGET',
79
- payload: { rowIdx: widgetConfig.rowIdx, colIdx: widgetConfig.colIdx, uid: widgetConfig.uid }
81
+ payload: { uid: widgetConfig.uid as string }
80
82
  })
81
83
  }
82
84
 
@@ -102,7 +104,10 @@ const Widget = ({ widgetConfig, addVisualization, type }: WidgetProps) => {
102
104
 
103
105
  const editWidget = () => {
104
106
  if (!widgetConfig) return
105
- dispatch({ type: 'UPDATE_VISUALIZATION', payload: { vizKey: widgetConfig.uid, configureData: { editing: true } } })
107
+ dispatch({
108
+ type: 'UPDATE_VISUALIZATION',
109
+ payload: { vizKey: widgetConfig.uid as string, configureData: { editing: true } }
110
+ })
106
111
  loadSampleData()
107
112
  }
108
113
 
@@ -156,6 +161,7 @@ const Widget = ({ widgetConfig, addVisualization, type }: WidgetProps) => {
156
161
  )}
157
162
  {iconHash[type]}
158
163
  <span>{labelHash[type]}</span>
164
+ <span>{title}</span>
159
165
  {widgetConfig?.newViz && type !== 'dashboardFilters' && (
160
166
  <span onClick={editWidget} className='config-needed'>
161
167
  Configuration needed
@@ -152,7 +152,7 @@ export const setAutoLoadDefaultValue = (
152
152
  if (!sharedFilter.active) {
153
153
  sharedFilter.active = defaultQueryParamValue || defaultValue
154
154
  } else {
155
- const currentOption = dropdownOptions.find(option => option.value === sharedFilter.active)
155
+ const currentOption = dropdownOptions.find(option => option.value == sharedFilter.active) // loose equality required: 2017 should equal '2017'
156
156
  sharedFilter.active = currentOption ? currentOption.value : defaultValue
157
157
  }
158
158
  }
package/src/index.tsx CHANGED
@@ -2,6 +2,7 @@ import React from 'react'
2
2
  import ReactDOM from 'react-dom/client'
3
3
 
4
4
  import MultiDashboardWrapper from './CdcDashboard'
5
+ import '@cdc/core/styles/cove-main.scss'
5
6
  import './coreStyles_dashboard.scss'
6
7
 
7
8
  let isEditor = window.location.href.includes('editor=true')
@@ -138,7 +138,6 @@
138
138
  }
139
139
 
140
140
  .btn {
141
-
142
141
  // Expand and Collapse Buttons for Multiviz Dashboard
143
142
  &.expand-collapse-buttons {
144
143
  background-color: var(--lightestGray);
@@ -163,13 +162,6 @@
163
162
  margin: 15px 0 0;
164
163
  }
165
164
 
166
- .data-table-container {
167
- margin: 20px 0 0;
168
- &.download-link-above {
169
- margin: 0;
170
- }
171
- }
172
-
173
165
  .collapsable-multiviz-container {
174
166
  position: relative;
175
167
  border: var(--lightGray) 1px solid;
@@ -193,8 +185,7 @@
193
185
  position: relative;
194
186
  }
195
187
  @include breakpoint(xs) {
196
- $font-small: 0.7em;
197
- font-size: $font-small + 0.2em;
188
+ font-size: 0.9em;
198
189
  }
199
190
  }
200
191
  .data-table-heading {
@@ -283,8 +274,6 @@
283
274
  }
284
275
 
285
276
  .cdc-dashboard-inner-container {
286
- margin: 1em;
287
-
288
277
  &.is-editor {
289
278
  margin-top: 7em;
290
279
  }
@@ -9,12 +9,12 @@ import { SharedFilter } from '../types/SharedFilter'
9
9
  type ADD_FOOTNOTE = Action<'ADD_FOOTNOTE', { id: string; rowIndex: number; config: Footnotes }>
10
10
  type ADD_VISUALIZATION = Action<'ADD_VISUALIZATION', { rowIdx: number; colIdx: number; newViz: AnyVisualization }>
11
11
  type APPLY_CONFIG = Action<'APPLY_CONFIG', [Config, Object?]>
12
- type DELETE_WIDGET = Action<'DELETE_WIDGET', { rowIdx: number; colIdx: number; uid: string }>
12
+ type DELETE_WIDGET = Action<'DELETE_WIDGET', { uid: string }>
13
13
  type MOVE_VISUALIZATION = Action<
14
14
  'MOVE_VISUALIZATION',
15
15
  { rowIdx: number; colIdx: number; widget: AnyVisualization & { rowIdx: number; colIdx: number } }
16
16
  >
17
- type SET_CONFIG = Action<'SET_CONFIG', Partial<Config>>
17
+ type SET_CONFIG = Action<'SET_CONFIG', Partial<Config> & { activeDashboard?: number }>
18
18
  type UPDATE_CONFIG = Action<'UPDATE_CONFIG', [Config, Object?]>
19
19
  type SET_DATA = Action<'SET_DATA', Record<string, any[]>>
20
20
  type SET_LOADING = Action<'SET_LOADING', boolean>
@@ -4,20 +4,20 @@ import { MultiDashboardConfig } from '../types/MultiDashboard'
4
4
  import DashboardActions from './dashboard.actions'
5
5
  import { devToolsWrapper } from '@cdc/core/helpers/withDevTools'
6
6
  import { Tab } from '../types/Tab'
7
- import { DashboardConfig } from '../types/DashboardConfig'
7
+ import { Dashboard } from '../types/Dashboard'
8
8
  import { ConfigRow } from '../types/ConfigRow'
9
9
  import { AnyVisualization } from '@cdc/core/types/Visualization'
10
10
  import { initialState } from '../DashboardContext'
11
11
 
12
12
  type BlankMultiConfig = {
13
- dashboard: Partial<DashboardConfig>
13
+ dashboard: Partial<Dashboard>
14
14
  rows: Partial<ConfigRow>[]
15
15
  visualizations: Record<string, Object>
16
16
  table: Object
17
17
  }
18
18
 
19
19
  const createBlankDashboard: () => BlankMultiConfig = () => ({
20
- dashboard: {},
20
+ dashboard: { sharedFilters: [] },
21
21
  rows: [{ columns: [{ width: 12 }] }],
22
22
  visualizations: {},
23
23
  table: {
@@ -71,7 +71,12 @@ const reducer = (state: DashboardState, action: DashboardActions): DashboardStat
71
71
  return { ...initialState, config, filteredData, data }
72
72
  }
73
73
  case 'SET_CONFIG': {
74
- return { ...state, config: { ...state.config, ...action.payload } }
74
+ if (
75
+ action.payload.activeDashboard === undefined ||
76
+ state.config.activeDashboard === action.payload.activeDashboard
77
+ ) {
78
+ return { ...state, config: { ...state.config, ...action.payload } }
79
+ } else return state // ignore SET_CONFIG calls that have the wrong activeDashboard due to async api fetching
75
80
  }
76
81
  case 'SET_DATA': {
77
82
  return { ...state, data: action.payload }
@@ -203,11 +208,9 @@ const reducer = (state: DashboardState, action: DashboardActions): DashboardStat
203
208
  return { ...state, config: { ...state.config, rows: newRows } }
204
209
  }
205
210
  case 'DELETE_WIDGET': {
206
- const { rowIdx, colIdx, uid } = action.payload
211
+ const { uid } = action.payload
207
212
  const newRows = _.cloneDeep(state.config.rows)
208
- newRows[rowIdx].columns[colIdx].widget = null
209
213
  const newVisualizations = _.cloneDeep(state.config.visualizations)
210
- delete newVisualizations[uid]
211
214
  const newSharedFilters = _.cloneDeep(state.config.dashboard.sharedFilters)
212
215
  if (newSharedFilters && newSharedFilters.length > 0) {
213
216
  newSharedFilters.forEach(sharedFilter => {
@@ -216,13 +219,19 @@ const reducer = (state: DashboardState, action: DashboardActions): DashboardStat
216
219
  }
217
220
  })
218
221
  }
222
+
223
+ const filteredRows = _.map(newRows, row => ({
224
+ ...row,
225
+ columns: _.filter(row.columns, column => column.widget !== uid)
226
+ }))
227
+
219
228
  return {
220
229
  ...state,
221
230
  config: {
222
231
  ...state.config,
223
232
  dashboard: { ...state.config.dashboard, sharedFilters: newSharedFilters },
224
233
  visualizations: newVisualizations,
225
- rows: newRows
234
+ rows: filteredRows
226
235
  }
227
236
  }
228
237
  }
@@ -5,6 +5,7 @@ import { ConfigRow } from './ConfigRow'
5
5
  import { AnyVisualization } from '@cdc/core/types/Visualization'
6
6
  import { Table } from '@cdc/core/types/Table'
7
7
  import { Dashboard } from './Dashboard'
8
+ import { Version } from '@cdc/core/types/Version'
8
9
 
9
10
  export type DashboardConfig = DataSet & {
10
11
  dashboard: Dashboard
@@ -18,4 +19,5 @@ export type DashboardConfig = DataSet & {
18
19
  runtime: Runtime
19
20
  downloadImageButton: boolean
20
21
  downloadPdfButton: boolean
22
+ version: Version
21
23
  }