@cdc/dashboard 4.26.2 → 4.26.3

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/LICENSE +201 -0
  2. package/dist/cdcdashboard-vr9HZwRt.es.js +6 -0
  3. package/dist/cdcdashboard.js +53345 -49681
  4. package/examples/custom/css/respiratory.css +1 -1
  5. package/examples/data/data-with-metadata.json +18 -0
  6. package/examples/default.json +7 -36
  7. package/examples/private/inline-markup.json +775 -0
  8. package/examples/private/recent-update.json +1456 -0
  9. package/examples/private/toggle.json +10137 -0
  10. package/package.json +9 -9
  11. package/src/CdcDashboard.tsx +2 -1
  12. package/src/CdcDashboardComponent.tsx +47 -27
  13. package/src/_stories/Dashboard.DataSetup.stories.tsx +6 -1
  14. package/src/_stories/Dashboard.Pages.stories.tsx +22 -0
  15. package/src/_stories/Dashboard.stories.tsx +4406 -7
  16. package/src/_stories/_mock/tab-simple-filter.json +153 -0
  17. package/src/components/DashboardFilters/DashboardFilters.tsx +19 -3
  18. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +7 -4
  19. package/src/components/DashboardFilters/DashboardFiltersEditor/components/APIModal.tsx +1 -1
  20. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +1 -2
  21. package/src/components/DashboardFilters/DashboardFiltersEditor/components/NestedDropDownDashboard.tsx +8 -7
  22. package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +8 -8
  23. package/src/components/DashboardFilters/_stories/DashboardFilters.stories.tsx +1 -1
  24. package/src/components/DashboardFilters/dashboardfilter.styles.css +3 -3
  25. package/src/components/DataDesignerModal.tsx +2 -2
  26. package/src/components/Header/Header.tsx +27 -5
  27. package/src/components/Header/index.scss +1 -1
  28. package/src/components/MultiConfigTabs/multiconfigtabs.styles.css +6 -6
  29. package/src/components/Row.tsx +21 -0
  30. package/src/components/Toggle/toggle-style.css +7 -7
  31. package/src/components/VisualizationRow.tsx +12 -4
  32. package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +1 -54
  33. package/src/components/VisualizationsPanel/visualizations-panel-styles.css +2 -2
  34. package/src/components/Widget/Widget.tsx +2 -2
  35. package/src/components/Widget/widget.styles.css +12 -12
  36. package/src/data/initial-state.js +1 -1
  37. package/src/helpers/addVisualization.ts +71 -0
  38. package/src/helpers/formatConfigBeforeSave.ts +1 -1
  39. package/src/helpers/getVizConfig.ts +13 -3
  40. package/src/helpers/iconHash.tsx +45 -36
  41. package/src/helpers/processDataLegacy.ts +19 -14
  42. package/src/helpers/tests/addVisualization.test.ts +52 -0
  43. package/src/helpers/tests/formatConfigBeforeSave.test.ts +81 -1
  44. package/src/scss/editor-panel.scss +1 -1
  45. package/src/scss/main.scss +164 -39
  46. package/src/store/dashboard.reducer.ts +1 -1
  47. package/src/test/CdcDashboard.test.jsx +2 -2
  48. package/src/test/CdcDashboardComponent.test.tsx +74 -0
  49. package/src/types/FilterStyles.ts +2 -1
  50. package/tests/fixtures/dashboard-config-with-metadata.json +89 -0
  51. package/vite.config.js +2 -2
  52. package/dist/cdcdashboard-Cf9_fbQf.es.js +0 -6
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@cdc/dashboard",
3
- "version": "4.26.2",
3
+ "version": "4.26.3",
4
4
  "description": "React component for combining multiple visualizations into a single dashboard",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Matthew Pallansch <mpallansch@adittech.com>",
7
7
  "bugs": "https://github.com/CDCgov/cdc-open-viz/issues",
8
8
  "dependencies": {
9
- "@cdc/chart": "^4.26.2",
10
- "@cdc/core": "^4.26.2",
11
- "@cdc/data-bite": "^4.26.2",
12
- "@cdc/filtered-text": "^4.26.2",
13
- "@cdc/map": "^4.26.2",
14
- "@cdc/markup-include": "^4.26.2",
15
- "@cdc/waffle-chart": "^4.26.2",
9
+ "@cdc/chart": "^4.26.3",
10
+ "@cdc/core": "^4.26.3",
11
+ "@cdc/data-bite": "^4.26.3",
12
+ "@cdc/filtered-text": "^4.26.3",
13
+ "@cdc/map": "^4.26.3",
14
+ "@cdc/markup-include": "^4.26.3",
15
+ "@cdc/waffle-chart": "^4.26.3",
16
16
  "js-base64": "^2.5.2",
17
17
  "react-accessible-accordion": "^5.0.1",
18
18
  "react-dnd": "^16.0.1",
@@ -26,7 +26,7 @@
26
26
  "vite-plugin-css-injected-by-js": "^2.4.0",
27
27
  "vite-plugin-svgr": "^4.2.0"
28
28
  },
29
- "gitHead": "be3413e8e1149abf94225108f86a7910f56e0616",
29
+ "gitHead": "d50e45a074fbefa56cac904917e707d57f237737",
30
30
  "main": "dist/cdcdashboard",
31
31
  "moduleName": "CdcDashboard",
32
32
  "peerDependencies": {
@@ -91,11 +91,12 @@ const MultiDashboardWrapper: React.FC<MultiDashboardProps> = ({
91
91
  return prepareDatasets(newConfig)
92
92
  } else {
93
93
  const dataKey = newConfig.dataFileName || 'backwards-compatibility'
94
- const data = await processDataLegacy(config)
94
+ const { data, dataMetadata } = await processDataLegacy(config)
95
95
 
96
96
  const datasetsFull = {}
97
97
  datasetsFull[dataKey] = {
98
98
  data,
99
+ dataMetadata,
99
100
  dataDescription: newConfig.dataDescription
100
101
  }
101
102
  newConfig.datasets = datasetsFull
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useCallback, useMemo, useReducer, useContext } from 'react'
1
+ import React, { useState, useEffect, useCallback, useMemo, useReducer, useContext, useRef } from 'react'
2
2
  import 'whatwg-fetch'
3
3
  import ResizeObserver from 'resize-observer-polyfill'
4
4
 
@@ -39,7 +39,9 @@ import { type SharedFilter } from './types/SharedFilter'
39
39
  import { type WCMSProps } from '@cdc/core/types/WCMSProps'
40
40
  import { type InitialState } from './types/InitialState'
41
41
  import MultiTabs from './components/MultiConfigTabs'
42
- import _ from 'lodash'
42
+ import cloneDeep from 'lodash/cloneDeep'
43
+ import pick from 'lodash/pick'
44
+ import pickBy from 'lodash/pickBy'
43
45
  import EditorContext from '@cdc/core/contexts/EditorContext'
44
46
  import { APIFilterDropdowns } from './components/DashboardFilters'
45
47
  import { ViewPort } from '@cdc/core/types/ViewPort'
@@ -47,7 +49,7 @@ import VisualizationRow from './components/VisualizationRow'
47
49
  import { getVizConfig } from './helpers/getVizConfig'
48
50
  import { getFilteredData } from './helpers/getFilteredData'
49
51
  import { getVizRowColumnLocator } from './helpers/getVizRowColumnLocator'
50
- import Layout from '@cdc/core/components/Layout'
52
+ import { Responsive, VisualizationContainer } from '@cdc/core/components/Layout'
51
53
  import * as reloadURLHelpers from './helpers/reloadURLHelpers'
52
54
  import { addValuesToDashboardFilters } from './helpers/addValuesToDashboardFilters'
53
55
  import { DashboardFilters } from './types/DashboardFilters'
@@ -207,9 +209,9 @@ export default function CdcDashboard({
207
209
 
208
210
  setAPILoading(true)
209
211
  await fetchRemoteData(dataUrlFinal)
210
- .then(responseData => {
211
- let data: any[] = responseData
212
- if (responseData && dataset.dataDescription) {
212
+ .then(({ data: fetchedData, dataMetadata }) => {
213
+ let data: any[] = fetchedData
214
+ if (data && dataset.dataDescription) {
213
215
  try {
214
216
  data = transform.autoStandardize(data)
215
217
  data = transform.developerStandardize(data, dataset.dataDescription)
@@ -219,6 +221,7 @@ export default function CdcDashboard({
219
221
  }
220
222
  }
221
223
  newDatasets[datasetKey].data = data
224
+ newDatasets[datasetKey].dataMetadata = dataMetadata
222
225
  newDatasets[datasetKey].runtimeDataUrl = dataUrlFinal
223
226
  newData[datasetKey] = data
224
227
  })
@@ -236,7 +239,7 @@ export default function CdcDashboard({
236
239
  }
237
240
  }
238
241
 
239
- const datasetsWithFiles = _.pickBy(newDatasets, dataset => !dataset.dataUrl)
242
+ const datasetsWithFiles = pickBy(newDatasets, dataset => !dataset.dataUrl)
240
243
 
241
244
  if (dataWasFetched || Object.keys(datasetsWithFiles).length) {
242
245
  const dataFiles = Object.keys(datasetsWithFiles).reduce((acc, key) => {
@@ -291,7 +294,7 @@ export default function CdcDashboard({
291
294
  }
292
295
 
293
296
  const setSharedFilter = (key, datum) => {
294
- const { config: newConfig, filteredData } = _.cloneDeep(state)
297
+ const { config: newConfig, filteredData } = cloneDeep(state)
295
298
 
296
299
  for (let i = 0; i < newConfig.dashboard.sharedFilters.length; i++) {
297
300
  const filter = newConfig.dashboard.sharedFilters[i]
@@ -319,7 +322,7 @@ export default function CdcDashboard({
319
322
  return acc
320
323
  }, {})
321
324
  const newConfig = { ...state, data: { ...data, ...newDatasets } }
322
- const newFilteredData = getFilteredData(newConfig, _.cloneDeep(filteredData))
325
+ const newFilteredData = getFilteredData(newConfig, cloneDeep(filteredData))
323
326
  dispatch({ type: 'SET_FILTERED_DATA', payload: newFilteredData })
324
327
  dispatch({ type: 'SET_DATA', payload: { ...data, ...newDatasets } })
325
328
  } catch (e) {
@@ -375,14 +378,14 @@ export default function CdcDashboard({
375
378
 
376
379
  const updateChildConfig = (visualizationKey, newConfig) => {
377
380
  const config = cloneConfig(state.config)
378
- const updatedConfig = _.pick(config, ['visualizations', 'multiDashboards'])
381
+ const updatedConfig = pick(config, ['visualizations', 'multiDashboards'])
379
382
  updatedConfig.visualizations[visualizationKey] = newConfig
380
383
  updatedConfig.visualizations[visualizationKey].formattedData = config.visualizations[visualizationKey].formattedData
381
384
  if (config.multiDashboards) {
382
385
  const activeDashboard = config.activeDashboard
383
386
  const multiDashboards = [...config.multiDashboards]
384
387
  const label = multiDashboards[activeDashboard].label
385
- const toSave = { label, visualizations: updatedConfig.visualizations, ..._.pick(config, ['dashboard', 'rows']) }
388
+ const toSave = { label, visualizations: updatedConfig.visualizations, ...pick(config, ['dashboard', 'rows']) }
386
389
  multiDashboards[activeDashboard] = toSave
387
390
  updatedConfig.multiDashboards = multiDashboards
388
391
  }
@@ -394,17 +397,31 @@ export default function CdcDashboard({
394
397
  }
395
398
  }
396
399
 
397
- const resizeObserver = new ResizeObserver(entries => {
398
- for (let entry of entries) {
399
- let newViewport = getViewport(entry.contentRect.width)
400
+ const resizeObserverRef = useRef<ResizeObserver | null>(null)
400
401
 
401
- setCurrentViewport(newViewport)
402
+ const outerContainerRef = useCallback(node => {
403
+ if (resizeObserverRef.current) {
404
+ resizeObserverRef.current.disconnect()
405
+ resizeObserverRef.current = null
402
406
  }
403
- })
404
407
 
405
- const outerContainerRef = useCallback(node => {
406
408
  if (node !== null) {
407
- resizeObserver.observe(node)
409
+ resizeObserverRef.current = new ResizeObserver(entries => {
410
+ for (let entry of entries) {
411
+ const newViewport = getViewport(entry.contentRect.width)
412
+ setCurrentViewport(newViewport)
413
+ }
414
+ })
415
+ resizeObserverRef.current.observe(node)
416
+ }
417
+ }, [])
418
+
419
+ useEffect(() => {
420
+ return () => {
421
+ if (resizeObserverRef.current) {
422
+ resizeObserverRef.current.disconnect()
423
+ resizeObserverRef.current = null
424
+ }
408
425
  }
409
426
  }, [])
410
427
 
@@ -497,7 +514,7 @@ export default function CdcDashboard({
497
514
  autoDismiss={true}
498
515
  />
499
516
  ))}
500
- <Layout.Responsive isEditor={isEditor}>
517
+ <Responsive isEditor={isEditor}>
501
518
  <div className={`cdc-dashboard-inner-container${isEditor ? ' is-editor' : ''}`}>
502
519
  <Title
503
520
  title={title}
@@ -640,16 +657,11 @@ export default function CdcDashboard({
640
657
  })
641
658
  .filter(Boolean)}
642
659
  </div>
643
- </Layout.Responsive>
660
+ </Responsive>
644
661
  </>
645
662
  )
646
663
  }
647
664
 
648
- const dashboardContainerClasses = ['cdc-open-viz-module', 'type-dashboard', `${currentViewport}`]
649
- if (isEditor) {
650
- dashboardContainerClasses.push('isDashboardEditor')
651
- }
652
-
653
665
  return (
654
666
  <GlobalContextProvider>
655
667
  <DashboardContext.Provider
@@ -666,9 +678,17 @@ export default function CdcDashboard({
666
678
  }}
667
679
  >
668
680
  <DashboardDispatchContext.Provider value={dispatch}>
669
- <div className={dashboardContainerClasses.join(' ')} ref={outerContainerRef} data-download-id={imageId}>
681
+ <VisualizationContainer
682
+ className={isEditor ? 'is-dashboard-editor' : undefined}
683
+ config={state.config}
684
+ currentViewport={currentViewport}
685
+ imageId={imageId}
686
+ isEditor={false}
687
+ ref={outerContainerRef}
688
+ renderResponsive={false}
689
+ >
670
690
  {body}
671
- </div>
691
+ </VisualizationContainer>
672
692
  <OverlayFrame />
673
693
  </DashboardDispatchContext.Provider>
674
694
  </DashboardContext.Provider>
@@ -159,7 +159,12 @@ export const MultiVizConfigurationWorkflow: Story = {
159
159
  // ========================================================================
160
160
  // STEP 11: Click "Vertical Values for map" button
161
161
  // ========================================================================
162
- await sleep(500)
162
+ await waitFor(
163
+ () => {
164
+ expect(canvas.getByRole('button', { name: /vertical values for map/i })).toBeTruthy()
165
+ },
166
+ { timeout: 5000 }
167
+ )
163
168
 
164
169
  const verticalValuesButton = canvas.getByRole('button', { name: /vertical values for map/i })
165
170
  await user.click(verticalValuesButton)
@@ -0,0 +1,22 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
+ import { assertVisualizationRendered } from '@cdc/core/helpers/testing'
3
+ import Dashboard from '../CdcDashboard'
4
+
5
+ const meta: Meta<typeof Dashboard> = {
6
+ title: 'Pages/NWSS',
7
+ component: Dashboard
8
+ }
9
+
10
+ export default meta
11
+ type Story = StoryObj<typeof Dashboard>
12
+
13
+ export const FluA_Top_Modules: Story = {
14
+ name: 'FluA Top Modules',
15
+ args: {
16
+ configUrl: 'https://www.cdc.gov/nwss/rv/modules/flua/flua-top-modules.json',
17
+ isEditor: false
18
+ },
19
+ play: async ({ canvasElement }) => {
20
+ await assertVisualizationRendered(canvasElement)
21
+ }
22
+ }