@cdc/dashboard 4.23.6 → 4.23.8

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.
@@ -147,6 +147,9 @@
147
147
  "specialClasses": [
148
148
  "N/A"
149
149
  ]
150
+ },
151
+ "dataTable": {
152
+
150
153
  }
151
154
  },
152
155
  "chart1": {
@@ -535,6 +535,66 @@
535
535
  "state": "Florida"
536
536
  }
537
537
  ]
538
+ },
539
+ "data3": {
540
+ "data": [
541
+ {
542
+ "Insured Rate": 8,
543
+ "Coverage Status": "Insured",
544
+ "FIPS Codes": "06071",
545
+ "Year (Good filter option)": "2010",
546
+ "link": ""
547
+ },
548
+ {
549
+ "Insured Rate": 0,
550
+ "Coverage Status": "Insured",
551
+ "FIPS Codes": "55005",
552
+ "Year (Good filter option)": "2010",
553
+ "link": "https://cdc.gov"
554
+ },
555
+ {
556
+ "Insured Rate": 25,
557
+ "Coverage Status": "Insured",
558
+ "FIPS Codes": "12103",
559
+ "Year (Good filter option)": "2010",
560
+ "link": ""
561
+ },
562
+ {
563
+ "Insured Rate": 25,
564
+ "Coverage Status": "Insured",
565
+ "FIPS Codes": "32005",
566
+ "Year (Good filter option)": "2010",
567
+ "link": ""
568
+ },
569
+ {
570
+ "Insured Rate": 18,
571
+ "Coverage Status": "Insured",
572
+ "FIPS Codes": "06075",
573
+ "Year (Good filter option)": "2010",
574
+ "link": ""
575
+ },
576
+ {
577
+ "Insured Rate": 3,
578
+ "Coverage Status": "Insured",
579
+ "FIPS Codes": "06027",
580
+ "Year (Good filter option)": "2010",
581
+ "link": ""
582
+ },
583
+ {
584
+ "Insured Rate": 25,
585
+ "Coverage Status": "Insured",
586
+ "FIPS Codes": "06029",
587
+ "Year (Good filter option)": "2010",
588
+ "link": ""
589
+ },
590
+ {
591
+ "Insured Rate": 60,
592
+ "Coverage Status": "Insured",
593
+ "FIPS Codes": "06065",
594
+ "Year (Good filter option)": "2010",
595
+ "link": ""
596
+ }
597
+ ]
538
598
  }
539
599
  },
540
600
  "runtime": {},
package/index.html CHANGED
@@ -21,8 +21,8 @@
21
21
  <body>
22
22
  <!-- <div class="react-container" data-config="/examples/default.json"></div> -->
23
23
  <!-- <div class="react-container" data-config="/examples/default-multi-dataset.json"></div> -->
24
- <!-- <div class="react-container" data-config="/examples/default-filter-control.json"></div> -->
25
- <div class="react-container" data-config="/examples/shared-filters.json"></div>
24
+ <div class="react-container" data-config="/examples/default-filter-control.json"></div>
25
+ <!-- <div class="react-container" data-config="/examples/private/bar-color.json"></div> -->
26
26
  <!-- <div class="react-container" data-config="/examples/private/totals.json"></div> -->
27
27
  <!-- <div class="react-container" data-config="/examples/private/totals-two.json"></div> -->
28
28
  <script type="module" src="./src/index.jsx"></script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdc/dashboard",
3
- "version": "4.23.6",
3
+ "version": "4.23.8",
4
4
  "description": "React component for combining multiple visualizations into a single dashboard",
5
5
  "moduleName": "CdcDashboard",
6
6
  "main": "dist/cdcdashboard",
@@ -25,13 +25,13 @@
25
25
  },
26
26
  "license": "Apache-2.0",
27
27
  "dependencies": {
28
- "@cdc/chart": "^4.23.6",
29
- "@cdc/core": "^4.23.6",
30
- "@cdc/data-bite": "^4.23.6",
31
- "@cdc/filtered-text": "^4.23.6",
32
- "@cdc/map": "^4.23.6",
33
- "@cdc/markup-include": "^4.23.6",
34
- "@cdc/waffle-chart": "^4.23.6",
28
+ "@cdc/chart": "^4.23.8",
29
+ "@cdc/core": "^4.23.8",
30
+ "@cdc/data-bite": "^4.23.8",
31
+ "@cdc/filtered-text": "^4.23.8",
32
+ "@cdc/map": "^4.23.8",
33
+ "@cdc/markup-include": "^4.23.8",
34
+ "@cdc/waffle-chart": "^4.23.8",
35
35
  "html-react-parser": "^3.0.8",
36
36
  "js-base64": "^2.5.2",
37
37
  "papaparse": "^5.3.0",
@@ -47,5 +47,5 @@
47
47
  "react": "^18.2.0",
48
48
  "react-dom": "^18.2.0"
49
49
  },
50
- "gitHead": "aaed0388b487adfeb3e7e278b4ce74df09cbaade"
50
+ "gitHead": "ba0a072a40c430baf121ad5ece0165f52a414b86"
51
51
  }
@@ -97,6 +97,7 @@ const VisualizationsPanel = ({ loadConfig, config }) => (
97
97
  <Widget addVisualization={() => addVisualization('waffle-chart', '')} type='waffle-chart' />
98
98
  <Widget addVisualization={() => addVisualization('markup-include', '')} type='markup-include' />
99
99
  <Widget addVisualization={() => addVisualization('filtered-text', '')} type='filtered-text' />
100
+ <Widget addVisualization={() => addVisualization('filter-dropdowns', '')} type='filter-dropdowns' />
100
101
  </div>
101
102
  <span className='subheading-3'>Advanced</span>
102
103
  <AdvancedEditor loadConfig={loadConfig} state={config} />
@@ -283,6 +284,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
283
284
  let add = true
284
285
 
285
286
  filters.forEach(filter => {
287
+ // eslint-disable-next-line eqeqeq
286
288
  if (filter.type !== 'url' && row[filter.columnName] != filter.active) {
287
289
  add = false
288
290
  }
@@ -416,7 +418,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
416
418
  setConfig(updatedConfig)
417
419
  }
418
420
 
419
- const Filters = () => {
421
+ const Filters = ({ hide }) => {
420
422
  const changeFilterActive = (index, value) => {
421
423
  let dashboardConfig = { ...config.dashboard }
422
424
 
@@ -445,7 +447,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
445
447
  const announceChange = text => {}
446
448
 
447
449
  return config.dashboard.sharedFilters.map((singleFilter, index) => {
448
- if (singleFilter.type !== 'url' && !singleFilter.showDropdown) return <></>
450
+ if ((singleFilter.type !== 'url' && !singleFilter.showDropdown) || (hide && hide.indexOf(index) !== -1)) return <></>
449
451
 
450
452
  const values = []
451
453
 
@@ -466,21 +468,23 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
466
468
  })
467
469
 
468
470
  return (
469
- <section className='dashboard-filters-section' key={`${singleFilter.key}-filtersection-${index}`}>
470
- <label htmlFor={`filter-${index}`}>{singleFilter.key}</label>
471
- <select
472
- id={`filter-${index}`}
473
- className='filter-select'
474
- data-index='0'
475
- value={singleFilter.active}
476
- onChange={val => {
477
- changeFilterActive(index, val.target.value)
478
- announceChange(`Filter ${singleFilter.key} value has been changed to ${val.target.value}, please reference the data table to see updated values.`)
479
- }}
480
- >
481
- {values}
482
- </select>
483
- </section>
471
+ <div className='cove-dashboard-filters'>
472
+ <section className='dashboard-filters-section' key={`${singleFilter.key}-filtersection-${index}`}>
473
+ <label htmlFor={`filter-${index}`}>{singleFilter.key}</label>
474
+ <select
475
+ id={`filter-${index}`}
476
+ className='filter-select'
477
+ data-index='0'
478
+ value={singleFilter.active}
479
+ onChange={val => {
480
+ changeFilterActive(index, val.target.value)
481
+ announceChange(`Filter ${singleFilter.key} value has been changed to ${val.target.value}, please reference the data table to see updated values.`)
482
+ }}
483
+ >
484
+ {values}
485
+ </select>
486
+ </section>
487
+ </div>
484
488
  )
485
489
  })
486
490
  }
@@ -596,6 +600,14 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
596
600
  </>
597
601
  )
598
602
  break
603
+ case 'filter-dropdowns':
604
+ body = (
605
+ <>
606
+ <Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor='Filter Dropdowns' />
607
+ <Filters hide={visualizationConfig.hide} />
608
+ </>
609
+ )
610
+ break
599
611
  default:
600
612
  body = <></>
601
613
  break
@@ -622,18 +634,13 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
622
634
  {/* Title */}
623
635
  {title && (
624
636
  <div role='heading' aria-level='3' className={`dashboard-title ${config.dashboard.theme ?? 'theme-blue'}`}>
625
- {title}
637
+ {parse(title)}
626
638
  </div>
627
639
  )}
628
640
  {/* Description */}
629
641
  {description && <div className='subtext'>{parse(description)}</div>}
630
642
  {/* Filters */}
631
- {config.dashboard.sharedFilters && (
632
- <div className='cove-dashboard-filters'>
633
- {' '}
634
- <Filters />
635
- </div>
636
- )}
643
+ {config.dashboard.sharedFilters && Object.keys(config.visualizations).filter(vizKey => config.visualizations[vizKey].visualizationType === 'filter-dropdowns').length === 0 && <Filters />}
637
644
 
638
645
  {/* Visualizations */}
639
646
  {config.rows &&
@@ -748,6 +755,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
748
755
  isDashboard={true}
749
756
  />
750
757
  )}
758
+ {visualizationConfig.type === 'filter-dropdowns' && <Filters hide={visualizationConfig.hide} />}
751
759
  </div>
752
760
  </React.Fragment>
753
761
  )
@@ -45,9 +45,23 @@ const Header = ({ setPreview, tabSelected, setTabSelected, back, subEditor = nul
45
45
 
46
46
  const removeFilter = index => {
47
47
  let dashboardConfig = { ...config.dashboard }
48
+ let visualizations = { ...config.visualizations }
48
49
 
49
50
  dashboardConfig.sharedFilters.splice(index, 1)
50
51
 
52
+ Object.keys(visualizations).forEach(vizKey => {
53
+ if(visualizations[vizKey].visualizationType === 'filter-dropdowns' && visualizations[vizKey].hide && visualizations[vizKey].hide.length > 0){
54
+ if(visualizations[vizKey].hide.indexOf(index) !== -1){
55
+ visualizations[vizKey].hide.splice(visualizations[vizKey].hide.indexOf(index), 1)
56
+ }
57
+ visualizations[vizKey].hide.forEach((hideIndex, i) => {
58
+ if(hideIndex > index){
59
+ visualizations[vizKey].hide[i] = hideIndex - 1
60
+ }
61
+ })
62
+ }
63
+ })
64
+
51
65
  // Ensures URL filters refresh after filter removal
52
66
  if (dashboardConfig.datasets) {
53
67
  Object.keys(dashboardConfig.datasets).forEach(datasetKey => {
@@ -55,7 +69,7 @@ const Header = ({ setPreview, tabSelected, setTabSelected, back, subEditor = nul
55
69
  })
56
70
  }
57
71
 
58
- updateConfig({ ...config, dashboard: dashboardConfig })
72
+ updateConfig({ ...config, visualizations, dashboard: dashboardConfig })
59
73
 
60
74
  overlay?.actions.toggleOverlay()
61
75
  }
@@ -25,7 +25,8 @@ const iconHash = {
25
25
  'single-state': <Icon display='mapAl' base />,
26
26
  gear: <Icon display='gear' base />,
27
27
  tools: <Icon display='tools' base />,
28
- 'filtered-text': <Icon display='filtered-text' base />
28
+ 'filtered-text': <Icon display='filtered-text' base />,
29
+ 'filter-dropdowns': <Icon display='filter-dropdowns' base />
29
30
  }
30
31
 
31
32
  const labelHash = {
@@ -40,7 +41,8 @@ const labelHash = {
40
41
  'us-county': 'United States (State- or County-Level)',
41
42
  world: 'World',
42
43
  'single-state': 'U.S. State',
43
- 'filtered-text': 'filtered-text'
44
+ 'filtered-text': 'Filtered Text',
45
+ 'filter-dropdowns': 'Filter Dropdowns'
44
46
  }
45
47
 
46
48
  const Widget = ({ data = {}, addVisualization, type }) => {
@@ -175,9 +177,62 @@ const Widget = ({ data = {}, addVisualization, type }) => {
175
177
  )
176
178
  }
177
179
 
180
+ const filterHideModal = (configureData) => {
181
+
182
+ const onFilterHideChange = (e, index) => {
183
+ const visualizations = {...config.visualizations}
184
+
185
+ const currentVizKey = Object.keys(visualizations).find(vizKey => vizKey === configureData.uid)
186
+
187
+ if(currentVizKey){
188
+ const currentVizConfig = visualizations[currentVizKey]
189
+
190
+ if(currentVizConfig){
191
+ if(!currentVizConfig.hide) currentVizConfig.hide = []
192
+ if(!e.target.checked && currentVizConfig.hide.indexOf(index) === -1) {
193
+ visualizations[currentVizKey].hide.push(index)
194
+ } else if(e.target.checked && currentVizConfig.hide.indexOf(index) !== -1) {
195
+ visualizations[currentVizKey].hide.splice(currentVizConfig.hide.indexOf(index), 1)
196
+ }
197
+ }
198
+ }
199
+
200
+ updateConfig({...config, visualizations})
201
+ }
202
+
203
+ overlay?.actions.toggleOverlay()
204
+
205
+ return (
206
+ <Modal>
207
+ <Modal.Content>
208
+ <div>
209
+ Choose which filters to display:
210
+ </div>
211
+
212
+ {config.dashboard.sharedFilters && config.dashboard.sharedFilters.length > 0 && config.dashboard.sharedFilters.map((sharedFilter, index) => (
213
+ <label>
214
+ <input type="checkbox" defaultChecked={!configureData.hide || configureData.hide.indexOf(index) === -1} onChange={(e) => onFilterHideChange(e, index)} />
215
+ {sharedFilter.key}
216
+ </label>
217
+ ))}
218
+
219
+ {(!config.dashboard.sharedFilters || config.dashboard.sharedFilters.length === 0) && (
220
+ <>No dashboard filters added yet.</>
221
+ )}
222
+
223
+ <div>
224
+ <button style={{ margin: '1em' }} className='cove-button' onClick={() => overlay?.actions.toggleOverlay()}>
225
+ Continue
226
+ </button>
227
+ </div>
228
+ </Modal.Content>
229
+ </Modal>
230
+ )
231
+ }
232
+
178
233
  useEffect(() => {
179
234
  if (data.openModal) {
180
- overlay?.actions.openOverlay(dataDesignerModal(dataRef.current))
235
+ overlay?.actions.openOverlay(type === 'filter-dropdowns' ? filterHideModal(dataRef.current) : dataDesignerModal(dataRef.current))
181
236
 
182
237
  visualizations[data.uid].openModal = false
183
238
 
@@ -192,7 +247,7 @@ const Widget = ({ data = {}, addVisualization, type }) => {
192
247
  <div className='widget__content'>
193
248
  {data.rowIdx !== undefined && (
194
249
  <div className='widget-menu'>
195
- {((data.dataKey && data.dataDescription && data.formattedData) || type === 'markup-include') && (
250
+ {((data.dataKey && data.dataDescription && data.formattedData) || type === 'markup-include') && type !== 'filter-dropdowns' && (
196
251
  <button title='Configure Visualization' className='btn btn-configure' onClick={editWidget}>
197
252
  {iconHash['tools']}
198
253
  </button>
@@ -202,7 +257,7 @@ const Widget = ({ data = {}, addVisualization, type }) => {
202
257
  title='Configure Data'
203
258
  className='btn btn-configure'
204
259
  onClick={() => {
205
- overlay?.actions.openOverlay(dataDesignerModal(data))
260
+ overlay?.actions.openOverlay(type === 'filter-dropdowns' ? filterHideModal(data) : dataDesignerModal(data))
206
261
  }}
207
262
  >
208
263
  {iconHash['gear']}
@@ -215,7 +270,7 @@ const Widget = ({ data = {}, addVisualization, type }) => {
215
270
  )}
216
271
  {iconHash[type]}
217
272
  <span>{labelHash[type]}</span>
218
- {data.newViz && (
273
+ {data.newViz && type !== 'filter-dropdowns' && (
219
274
  <span onClick={editWidget} className='config-needed'>
220
275
  Configuration needed
221
276
  </span>
@@ -239,6 +239,11 @@
239
239
  width: 100%;
240
240
  }
241
241
 
242
+ .cove-dashboard-filters {
243
+ display: inline-flex;
244
+ margin: 1em;
245
+ }
246
+
242
247
  @include breakpointClass(md) {
243
248
  .dashboard-row {
244
249
  flex-direction: row;
@@ -271,13 +276,6 @@
271
276
  }
272
277
  }
273
278
 
274
- @include breakpoint(md) {
275
- .cove-dashboard-filters {
276
- display: flex;
277
- gap: 30px;
278
- }
279
- }
280
-
281
279
  .dashboard-filters-section {
282
280
  margin: 0 0 1em;
283
281
  }