@cdc/editor 4.26.1 → 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.
package/index.html CHANGED
@@ -1,20 +1 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
6
- <style type="text/css">
7
- body {
8
- margin: 0;
9
- }
10
- .react-container {
11
- min-height: 100vh;
12
- }
13
- </style>
14
- <link rel="stylesheet prefetch" href="https://www.cdc.gov/TemplatePackage/5.0/css/app.min.css?_=71669" />
15
- </head>
16
- <body>
17
- <div class="react-container react--editor"></div>
18
- <script type="module" src="./src/index.jsx"></script>
19
- </body>
20
- </html>
1
+ <!-- index.html is generated by @cdc/core/generateViteConfig.js using the files in @cdc/core/devTemplate/ -->
package/package.json CHANGED
@@ -1,51 +1,49 @@
1
1
  {
2
2
  "name": "@cdc/editor",
3
- "version": "4.26.1",
3
+ "version": "4.26.3",
4
4
  "description": "React component for generating a new component entry",
5
- "moduleName": "CdcEditor",
6
- "main": "dist/cdceditor",
7
- "type": "module",
8
- "scripts": {
9
- "start": "vite --open",
10
- "build": "vite build",
11
- "preview": "vite preview",
12
- "graph": "nx graph",
13
- "prepublishOnly": "lerna run --scope @cdc/editor build",
14
- "test": "vitest run --reporter verbose",
15
- "test-watch": "vitest watch --reporter verbose",
16
- "test-watch:ui": "vitest --ui"
17
- },
18
- "repository": {
19
- "type": "git",
20
- "url": "git+https://github.com/CDCgov/cdc-open-viz",
21
- "directory": "packages/editor"
22
- },
23
- "bugs": {
24
- "url": "https://github.com/CDCgov/cdc-open-viz/issues"
25
- },
26
5
  "license": "Apache-2.0",
6
+ "bugs": "https://github.com/CDCgov/cdc-open-viz/issues",
27
7
  "dependencies": {
28
- "@cdc/chart": "^4.26.1",
29
- "@cdc/core": "^4.26.1",
30
- "@cdc/dashboard": "^4.26.1",
31
- "@cdc/data-bite": "^4.26.1",
32
- "@cdc/map": "^4.26.1",
33
- "@cdc/markup-include": "^4.26.1",
34
- "@cdc/waffle-chart": "^4.26.1",
35
- "axios": "^1.9.0",
8
+ "@cdc/chart": "^4.26.3",
9
+ "@cdc/core": "^4.26.3",
10
+ "@cdc/dashboard": "^4.26.3",
11
+ "@cdc/data-bite": "^4.26.3",
12
+ "@cdc/map": "^4.26.3",
13
+ "@cdc/markup-include": "^4.26.3",
14
+ "@cdc/waffle-chart": "^4.26.3",
15
+ "axios": "^1.13.2",
36
16
  "d3": "^7.9.0",
37
17
  "react-dropzone": "^14.3.8",
38
- "use-debounce": "^10.0.5"
39
- },
40
- "peerDependencies": {
41
- "react": "^18.2.0",
42
- "react-dom": "^18.2.0"
18
+ "use-debounce": "^10.1.0"
43
19
  },
44
20
  "devDependencies": {
45
21
  "@rollup/plugin-dsv": "^3.0.2",
46
- "@vitejs/plugin-react": "^4.3.4",
22
+ "@vitejs/plugin-react": "^5.1.2",
47
23
  "vite-plugin-css-injected-by-js": "^2.4.0",
48
24
  "vite-plugin-svgr": "^4.2.0"
49
25
  },
50
- "gitHead": "7e3b27098c4eb7a24bc9c3654ad53f88d6419f16"
26
+ "gitHead": "d50e45a074fbefa56cac904917e707d57f237737",
27
+ "main": "dist/cdceditor",
28
+ "moduleName": "CdcEditor",
29
+ "peerDependencies": {
30
+ "react": "^18.2.0",
31
+ "react-dom": "^18.2.0"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/CDCgov/cdc-open-viz",
36
+ "directory": "packages/editor"
37
+ },
38
+ "scripts": {
39
+ "build": "vite build",
40
+ "graph": "nx graph",
41
+ "prepublishOnly": "lerna run --scope @cdc/editor build",
42
+ "preview": "vite preview",
43
+ "start": "vite --open",
44
+ "test": "vitest run --reporter verbose",
45
+ "test-watch": "vitest watch --reporter verbose",
46
+ "test-watch:ui": "vitest --ui"
47
+ },
48
+ "type": "module"
51
49
  }
package/src/CdcEditor.tsx CHANGED
@@ -1,7 +1,4 @@
1
1
  import React, { useState, useEffect, useCallback, useReducer, useMemo } from 'react'
2
-
3
- // IE11
4
- // import 'core-js/stable' // temp remove, appears to be used with html2pdf.js which we're temp removing
5
2
  import ResizeObserver from 'resize-observer-polyfill'
6
3
 
7
4
  import getViewport from '@cdc/core/helpers/getViewport'
@@ -22,7 +19,6 @@ import { legacyConfigSupport } from './helpers/legacyConfigSupport'
22
19
 
23
20
  import './scss/main.scss'
24
21
  import editorReducer, { EditorState } from '@cdc/core/contexts/editor.reducer'
25
- import _ from 'lodash'
26
22
  import { cloneConfig } from '@cdc/core/helpers/cloneConfig'
27
23
  import { WCMSProps } from '@cdc/core/types/WCMSProps'
28
24
  import { devToolsStore } from '@cdc/core/helpers/withDevTools'
@@ -76,7 +72,7 @@ const CdcEditor: React.FC<WCMSProps> = ({ config: configObj, hostname, container
76
72
  }, [])
77
73
 
78
74
  useEffect(() => {
79
- let strippedConfig = stripConfig(state.config)
75
+ let strippedConfig = stripConfig(state.config, true)
80
76
 
81
77
  const parsedData = JSON.stringify(strippedConfig)
82
78
  // Emit the data in a regular JS event so it can be consumed by anything.
@@ -102,7 +98,7 @@ const CdcEditor: React.FC<WCMSProps> = ({ config: configObj, hostname, container
102
98
  <GlobalContextProvider>
103
99
  <ConfigContext.Provider value={{ ...state, setTempConfig: setTempConfigAndUpdate }}>
104
100
  <EditorDispatchContext.Provider value={dispatch}>
105
- <div className={`cdc-open-viz-module cdc-editor ${state.currentViewport}`} ref={outerContainerRef}>
101
+ <div className={`cove-visualization cdc-editor ${state.currentViewport}`} ref={outerContainerRef}>
106
102
  <Tabs className='top-level'>
107
103
  <TabPane title='1. Choose Visualization Type' className='choose-type'>
108
104
  <ChooseTab />
@@ -1,9 +1,29 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-vite'
2
2
  import CdcEditor from '../CdcEditor'
3
- import { within, userEvent } from 'storybook/test'
3
+ import { within, userEvent, expect } from 'storybook/test'
4
+ import ChartEditorConfig from '../../../chart/src/_stories/_mock/editor-tests/bar-chart-editor-test.json'
5
+ import MapConfig from '../../../map/src/_stories/_mock/default-patterns.json'
6
+ import DashboardConfig from '../../../dashboard/src/_stories/_mock/dashboard_no_filter.json'
7
+ import DataTableConfig from '../../../data-table/examples/data-table-example.json'
4
8
 
5
- const sleep = ms => {
6
- return new Promise(r => setTimeout(r, ms))
9
+ const loadConfigFromTextArea = async (canvasElement, config) => {
10
+ const user = userEvent.setup()
11
+ const textArea = canvasElement.querySelector('#pasteConfig') as HTMLTextAreaElement
12
+ const loadButton = canvasElement.querySelector('#load-data') as HTMLButtonElement
13
+
14
+ expect(textArea).toBeTruthy()
15
+ expect(loadButton).toBeTruthy()
16
+
17
+ await user.click(textArea)
18
+ await user.clear(textArea)
19
+ await user.paste(JSON.stringify(config))
20
+ await user.click(loadButton)
21
+ }
22
+
23
+ const assertImportDataTabAccessible = async canvas => {
24
+ const user = userEvent.setup()
25
+ await user.click(canvas.getByText('2. Import Data'))
26
+ await expect(canvas.findByText('Data Preview')).resolves.toBeTruthy()
7
27
  }
8
28
 
9
29
  const meta: Meta<typeof CdcEditor> = {
@@ -26,10 +46,95 @@ export const PreviewTableTests: Story = {
26
46
  play: async ({ canvasElement }) => {
27
47
  const canvas = within(canvasElement)
28
48
  const user = userEvent.setup()
29
- await sleep(1000)
30
- const mapButton = canvas.getByText('United States (State- or County-Level)')
49
+
50
+ const mapButton = await canvas.findByRole('button', { name: 'United States (State- or County-Level)' })
31
51
  await user.click(mapButton)
32
- const sampleData = canvas.getByText('United States: County Sample Data')
52
+
53
+ await user.click(canvas.getByText('2. Import Data'))
54
+
55
+ const sampleData = await canvas.findByText('United States: County Sample Data')
33
56
  await user.click(sampleData)
57
+
58
+ await expect(canvas.findByText('Data Preview')).resolves.toBeTruthy()
59
+ }
60
+ }
61
+
62
+ export const LoadChartJsonConfig: Story = {
63
+ args: {
64
+ config: {}
65
+ },
66
+ play: async ({ canvasElement }) => {
67
+ const canvas = within(canvasElement)
68
+ await loadConfigFromTextArea(canvasElement, ChartEditorConfig)
69
+ await assertImportDataTabAccessible(canvas)
70
+ }
71
+ }
72
+
73
+ export const LoadMapJsonConfig: Story = {
74
+ args: {
75
+ config: {}
76
+ },
77
+ play: async ({ canvasElement }) => {
78
+ const canvas = within(canvasElement)
79
+ await loadConfigFromTextArea(canvasElement, MapConfig)
80
+ await assertImportDataTabAccessible(canvas)
81
+ }
82
+ }
83
+
84
+ export const LoadDashboardJsonConfig: Story = {
85
+ args: {
86
+ config: {}
87
+ },
88
+ play: async ({ canvasElement }) => {
89
+ const canvas = within(canvasElement)
90
+ await loadConfigFromTextArea(canvasElement, DashboardConfig)
91
+ await assertImportDataTabAccessible(canvas)
92
+ }
93
+ }
94
+
95
+ export const LoadDataTableJsonConfig: Story = {
96
+ args: {
97
+ config: {}
98
+ },
99
+ play: async ({ canvasElement }) => {
100
+ const canvas = within(canvasElement)
101
+ await loadConfigFromTextArea(canvasElement, DataTableConfig)
102
+ await assertImportDataTabAccessible(canvas)
103
+ }
104
+ }
105
+
106
+ export const InvalidJsonShowsValidationAlert: Story = {
107
+ args: {
108
+ config: {}
109
+ },
110
+ play: async ({ canvasElement }) => {
111
+ const user = userEvent.setup()
112
+ const textArea = canvasElement.querySelector('#pasteConfig') as HTMLTextAreaElement
113
+ const loadButton = canvasElement.querySelector('#load-data') as HTMLButtonElement
114
+
115
+ expect(textArea).toBeTruthy()
116
+ expect(loadButton).toBeTruthy()
117
+
118
+ const originalAlert = window.alert
119
+ const originalOnError = window.onerror
120
+ let alertText = ''
121
+
122
+ window.alert = message => {
123
+ alertText = String(message)
124
+ }
125
+
126
+ window.onerror = () => true
127
+
128
+ try {
129
+ await user.click(textArea)
130
+ await user.clear(textArea)
131
+ await user.paste('{"broken": true, }')
132
+ await user.click(loadButton)
133
+
134
+ await expect(alertText).toBe('The JSON that was entered is invalid.')
135
+ } finally {
136
+ window.alert = originalAlert
137
+ window.onerror = originalOnError
138
+ }
34
139
  }
35
140
  }
@@ -0,0 +1,36 @@
1
+ import React from 'react'
2
+ import { render, waitFor } from '@testing-library/react'
3
+
4
+ import ConfigContext, { EditorDispatchContext } from '@cdc/core/contexts/EditorContext'
5
+ import ChooseTab from './ChooseTab'
6
+
7
+ describe('ChooseTab', () => {
8
+ it('dispatches EDITOR_SAVE once when tempConfig is present', async () => {
9
+ const dispatch = vi.fn()
10
+ const tempConfig = { type: 'chart', data: [{ x: 'A', y: 1 }] }
11
+
12
+ render(
13
+ <ConfigContext.Provider
14
+ value={
15
+ {
16
+ config: { type: 'chart' },
17
+ tempConfig,
18
+ errors: [],
19
+ currentViewport: 'lg',
20
+ globalActive: 0,
21
+ setTempConfig: vi.fn()
22
+ } as any
23
+ }
24
+ >
25
+ <EditorDispatchContext.Provider value={dispatch}>
26
+ <ChooseTab />
27
+ </EditorDispatchContext.Provider>
28
+ </ConfigContext.Provider>
29
+ )
30
+
31
+ await waitFor(() => {
32
+ expect(dispatch).toHaveBeenCalledTimes(1)
33
+ expect(dispatch).toHaveBeenCalledWith({ type: 'EDITOR_SAVE', payload: tempConfig })
34
+ })
35
+ })
36
+ })
@@ -1,33 +1,36 @@
1
- import React, { useContext, useState } from 'react'
1
+ import React, { useContext, useEffect, useState } from 'react'
2
2
  import '../scss/choose-vis-tab.scss'
3
3
 
4
4
  import ConfigContext, { EditorDispatchContext } from '@cdc/core/contexts/EditorContext'
5
5
  import Tooltip from '@cdc/core/components/ui/Tooltip'
6
6
 
7
- import DashboardIcon from '@cdc/core/assets/icon-dashboard.svg'
7
+ import AlabamaGraphic from '@cdc/core/assets/icon-map-alabama.svg'
8
+ import AreaChartIcon from '@cdc/core/assets/icon-area-chart.svg'
8
9
  import BarIcon from '@cdc/core/assets/icon-chart-bar.svg'
10
+ import BoxPlotIcon from '@cdc/core/assets/icon-chart-box-whisker.svg'
11
+ import CodeIcon from '@cdc/core/assets/icon-code.svg'
12
+ import ComboChartIcon from '@cdc/core/assets/icon-combo-chart.svg'
13
+ import DashboardIcon from '@cdc/core/assets/icon-dashboard.svg'
14
+ import DataBiteIcon from '@cdc/core/assets/icon-databite.svg'
15
+ import DeviationIcon from '@cdc/core/assets/icon-deviation-bar.svg'
16
+ import EpiChartIcon from '@cdc/core/assets/icon-epi-chart.svg'
17
+ import ForecastIcon from '@cdc/core/assets/icon-chart-forecast.svg'
18
+ import GaugeChartIcon from '@cdc/core/assets/icon-linear-gauge.svg'
19
+ import GlobeIcon from '@cdc/core/assets/icon-map-world.svg'
20
+ import HorizonChartIcon from '@cdc/core/assets/icon-chart-area.svg'
21
+ import HorizontalStackIcon from '@cdc/core/assets/icon-chart-bar-stacked.svg'
22
+ import Icon from '@cdc/core/components/ui/Icon'
9
23
  import LineIcon from '@cdc/core/assets/icon-chart-line.svg'
24
+ import PairedBarIcon from '@cdc/core/assets/icon-chart-bar-paired.svg'
10
25
  import PieIcon from '@cdc/core/assets/icon-chart-pie.svg'
11
- import GlobeIcon from '@cdc/core/assets/icon-map-world.svg'
26
+ import RadarChartIcon from '@cdc/core/assets/icon-chart-radar.svg'
27
+ import SankeyIcon from '@cdc/core/assets/icon-sankey.svg'
28
+ import ScatterPlotIcon from '@cdc/core/assets/icon-chart-scatterplot.svg'
29
+ import TableIcon from '@cdc/core/assets/icon-table.svg'
12
30
  import UsaIcon from '@cdc/core/assets/icon-map-usa.svg'
13
31
  import UsaRegionIcon from '@cdc/core/assets/usa-region-graphic.svg'
14
- import DataBiteIcon from '@cdc/core/assets/icon-databite.svg'
15
32
  import WaffleChartIcon from '@cdc/core/assets/icon-grid.svg'
16
- import AlabamaGraphic from '@cdc/core/assets/icon-map-alabama.svg'
17
- import PairedBarIcon from '@cdc/core/assets/icon-chart-bar-paired.svg'
18
- import HorizontalStackIcon from '@cdc/core/assets/icon-chart-bar-stacked.svg'
19
- import ScatterPlotIcon from '@cdc/core/assets/icon-chart-scatterplot.svg'
20
- import BoxPlotIcon from '@cdc/core/assets/icon-chart-box-whisker.svg'
21
- import AreaChartIcon from '@cdc/core/assets/icon-area-chart.svg'
22
- import GaugeChartIcon from '@cdc/core/assets/icon-linear-gauge.svg'
23
- import ForecastIcon from '@cdc/core/assets/icon-chart-forecast.svg'
24
- import DeviationIcon from '@cdc/core/assets/icon-deviation-bar.svg'
25
- import SankeyIcon from '@cdc/core/assets/icon-sankey.svg'
26
- import ComboChartIcon from '@cdc/core/assets/icon-combo-chart.svg'
27
- import EpiChartIcon from '@cdc/core/assets/icon-epi-chart.svg'
28
- import TableIcon from '@cdc/core/assets/icon-table.svg'
29
33
  import WarmingStripesIcon from '@cdc/core/assets/icon-warming-stripes.svg'
30
- import Icon from '@cdc/core/components/ui/Icon'
31
34
 
32
35
  import {
33
36
  convertVegaConfig,
@@ -48,6 +51,23 @@ interface ButtonProps {
48
51
  orientation?: string | null
49
52
  }
50
53
 
54
+ interface VizButtonProps extends ButtonProps {
55
+ activeVizButtonID?: number
56
+ onConfigure: (props: Record<string, unknown>) => void
57
+ }
58
+
59
+ const VizButton: React.FC<VizButtonProps> = ({ activeVizButtonID, onConfigure, ...buttonProps }) => {
60
+ const { label, icon, id } = buttonProps
61
+ const isActive = id === activeVizButtonID || 0
62
+
63
+ return (
64
+ <button className={isActive ? 'active' : ''} onClick={() => onConfigure(buttonProps)} aria-label={label}>
65
+ {icon}
66
+ <span className='mt-1'>{label}</span>
67
+ </button>
68
+ )
69
+ }
70
+
51
71
  const ChooseTab: React.FC = (): JSX.Element => {
52
72
  const { config, tempConfig } = useContext(ConfigContext)
53
73
 
@@ -56,6 +76,12 @@ const ChooseTab: React.FC = (): JSX.Element => {
56
76
  const dispatch = useContext(EditorDispatchContext)
57
77
  const rowLabels = ['General', , 'Charts', 'Maps']
58
78
 
79
+ useEffect(() => {
80
+ if (tempConfig) {
81
+ dispatch({ type: 'EDITOR_SAVE', payload: tempConfig })
82
+ }
83
+ }, [dispatch, tempConfig])
84
+
59
85
  const handleUpload = e => {
60
86
  const file = e.target.files[0]
61
87
  const reader = new FileReader()
@@ -72,12 +98,15 @@ const ChooseTab: React.FC = (): JSX.Element => {
72
98
  newConfig = JSON.parse(text)
73
99
  } catch (e) {
74
100
  alert('The JSON that was entered is invalid.')
75
- throw new Error()
101
+ return
76
102
  }
77
103
 
78
104
  const isVega = isVegaConfig(newConfig)
79
105
  if (isVega) {
80
106
  newConfig = importVegaConfig(newConfig)
107
+ if (!newConfig) {
108
+ return
109
+ }
81
110
  }
82
111
 
83
112
  dispatch({ type: 'EDITOR_SET_CONFIG', payload: newConfig })
@@ -109,7 +138,7 @@ const ChooseTab: React.FC = (): JSX.Element => {
109
138
 
110
139
  const errorText = vegaErrors.join('\n\n')
111
140
  alert(errorText)
112
- throw new Error(errorText)
141
+ return null
113
142
  }
114
143
 
115
144
  const generateNewConfig = props => {
@@ -171,25 +200,6 @@ const ChooseTab: React.FC = (): JSX.Element => {
171
200
  dispatch({ type: 'EDITOR_SET_GLOBALACTIVE', payload: 1 })
172
201
  }
173
202
 
174
- const VizButton: React.FC<ButtonProps> = props => {
175
- const { label, icon, id } = props
176
- const isActive = id === config?.activeVizButtonID || 0
177
- const handleClick = () => {
178
- configureTabs(props)
179
- }
180
-
181
- if (tempConfig) {
182
- dispatch({ type: 'EDITOR_SAVE', payload: tempConfig })
183
- }
184
-
185
- return (
186
- <button className={isActive ? 'active' : ''} onClick={handleClick} aria-label={label}>
187
- {icon}
188
- <span className='mt-1'>{label}</span>
189
- </button>
190
- )
191
- }
192
-
193
203
  return (
194
204
  <div className='choose-vis'>
195
205
  <a
@@ -218,7 +228,11 @@ const ChooseTab: React.FC = (): JSX.Element => {
218
228
  <li key={`${label}-button-${buttonIndex}`}>
219
229
  <Tooltip position='right'>
220
230
  <Tooltip.Target>
221
- <VizButton {...button} />
231
+ <VizButton
232
+ {...button}
233
+ activeVizButtonID={config?.activeVizButtonID}
234
+ onConfigure={configureTabs}
235
+ />
222
236
  </Tooltip.Target>
223
237
  <Tooltip.Content>{button.content}</Tooltip.Content>
224
238
  </Tooltip>
@@ -317,6 +331,16 @@ const buttons = [
317
331
  content: `Specify the calculation of a single data point (such as a percentage value) and present it on a horizontal
318
332
  scale.`
319
333
  },
334
+ {
335
+ id: 26,
336
+ category: 'General',
337
+ label: 'Markup Include',
338
+ type: 'markup-include',
339
+ subType: null,
340
+ orientation: null,
341
+ icon: <CodeIcon />,
342
+ content: 'Include custom HTML markup or embed content from external URLs.'
343
+ },
320
344
  {
321
345
  id: 17,
322
346
  category: 'General',
@@ -415,6 +439,16 @@ const buttons = [
415
439
  icon: <ForecastIcon />,
416
440
  content: 'Display a forecasting chart to predict future data trends.'
417
441
  },
442
+ {
443
+ id: 27,
444
+ category: 'Charts',
445
+ label: 'Horizon Chart',
446
+ type: 'chart',
447
+ subType: 'Horizon Chart',
448
+ orientation: 'vertical',
449
+ icon: <HorizonChartIcon />,
450
+ content: 'Display a horizon chart to visualize quantities over time in a smaller space.'
451
+ },
418
452
  {
419
453
  id: 12,
420
454
  category: 'Charts',
@@ -456,6 +490,16 @@ const buttons = [
456
490
  icon: <PieIcon />,
457
491
  content: 'Present the numerical proportions of a data series.'
458
492
  },
493
+ {
494
+ id: 27,
495
+ category: 'Charts',
496
+ label: 'Radar',
497
+ type: 'chart',
498
+ subType: 'Radar',
499
+ orientation: 'vertical',
500
+ icon: <RadarChartIcon />,
501
+ content: 'Compare multiple quantitative variables across categories using a radial layout.'
502
+ },
459
503
  {
460
504
  id: 10,
461
505
  category: 'Charts',
@@ -33,7 +33,8 @@ export default function ConfigureTab({ containerEl }) {
33
33
  if (
34
34
  config.visualizationType === 'Waffle' ||
35
35
  config.visualizationType === 'TP5 Waffle' ||
36
- config.visualizationType === 'Gauge'
36
+ config.visualizationType === 'Gauge' ||
37
+ config.visualizationType === 'TP5 Gauge'
37
38
  ) {
38
39
  return (
39
40
  <ErrorBoundary component='CdcWaffleChart'>
@@ -24,7 +24,7 @@ import { type Visualization } from '@cdc/core/types/Visualization'
24
24
  import { type DataSet } from '@cdc/core/types/DataSet'
25
25
 
26
26
  import './data-import.scss'
27
- import '@cdc/core/styles/v2/components/data-designer.scss'
27
+ import '@cdc/core/components/managers/data-designer.scss'
28
28
 
29
29
  import { errorMessages, maxFileSize } from '../../../helpers/errorMessages'
30
30
  import { displaySize } from '../helpers/displaySize'
@@ -39,6 +39,7 @@ import {
39
39
  parseVegaConfig,
40
40
  updateVegaData
41
41
  } from '@cdc/core/helpers/vegaConfig'
42
+ import { extractDataAndMetadata } from '@cdc/core/helpers/extractDataAndMetadata'
42
43
 
43
44
  const DataImport = () => {
44
45
  const { config, errors, tempConfig, sharepath } = useContext(ConfigContext)
@@ -179,12 +180,13 @@ const DataImport = () => {
179
180
  const filereader = new FileReader()
180
181
 
181
182
  filereader.onload = function () {
182
- const handleSetConfig = (newData: Object[], useTempConfig = false) => {
183
+ const handleSetConfig = (newData: Object[], useTempConfig = false, dataMetadata = {}) => {
183
184
  const setDataURL = keepURL && fileSourceType === 'url'
184
185
  if (config.type === 'dashboard') {
185
186
  const dataFileFormat = mimeType.split('/')[1].toUpperCase()
186
187
  const dataset = {
187
188
  data: newData,
189
+ dataMetadata,
188
190
  dataFileSize: fileSize,
189
191
  dataFileName: fileSource, // new file source
190
192
  dataFileSourceType: fileSourceType, // new file source type
@@ -210,6 +212,7 @@ const DataImport = () => {
210
212
  ...config,
211
213
  ...tempConfig,
212
214
  data: newData,
215
+ dataMetadata,
213
216
  dataFileName: fileSource, // new file source
214
217
  dataFileSourceType: fileSourceType, // new file source type
215
218
  formattedData: transform.developerStandardize(newData, config.dataDescription)
@@ -227,14 +230,16 @@ const DataImport = () => {
227
230
  if (config.vegaConfig) {
228
231
  return updateDataFromVegaData(result, fileSource, fileSourceType)
229
232
  }
230
- const text = transform.autoStandardize(result)
233
+ const { data: extractedData, dataMetadata } = extractDataAndMetadata(result)
234
+ const text = transform.autoStandardize(extractedData)
231
235
  if (config.data && config.series) {
232
236
  if (dataExists(text, config.series, config?.xAxis.dataKey)) {
233
- handleSetConfig(text, true)
237
+ handleSetConfig(text, true, dataMetadata)
234
238
  } else {
235
239
  resetEditor(
236
240
  {
237
241
  data: text,
242
+ dataMetadata,
238
243
  dataFileName: fileSource,
239
244
  dataFileSourceType: fileSourceType
240
245
  } as Visualization,
@@ -242,7 +247,7 @@ const DataImport = () => {
242
247
  )
243
248
  }
244
249
  } else {
245
- handleSetConfig(text)
250
+ handleSetConfig(text, false, dataMetadata)
246
251
  }
247
252
 
248
253
  if (editingDataset) {
@@ -3,20 +3,22 @@ import SampleDataContext from './samples/SampleDataContext'
3
3
  import { cityTemperature } from '@visx/mock-data'
4
4
 
5
5
  // Data Samples
6
- import validMapData from './samples/valid-data-map.csv?raw'
7
- import validMapDataFootnotes from './samples/valid-data-map-footnotes.csv?raw'
6
+ import pivotData from './samples/pivotData.json?raw'
7
+ import vaidWorldData from './samples/valid-world-data.json?raw'
8
+ import validAreaChart from './samples/valid-area-chart.json?raw'
9
+ import validBoxPlotData from './samples/valid-boxplot.csv?raw'
8
10
  import validChartData from './samples/valid-data-chart.csv?raw'
9
11
  import validCountyMapData from './samples/valid-county-data.csv?raw'
10
- import validGeoPoint from './samples/valid-geo-point.csv?raw'
11
- import validScatterPlot from './samples/valid-scatterplot.csv?raw'
12
- import validBoxPlotData from './samples/valid-boxplot.csv?raw'
13
- import validAreaChart from './samples/valid-area-chart.json?raw'
14
- import validWorldGeocodeData from './samples/valid-world-geocode.json?raw'
15
12
  import validForecastData from './samples/valid-forecast-data.csv?raw'
16
- import vaidWorldData from './samples/valid-world-data.json?raw'
13
+ import validGeoPoint from './samples/valid-geo-point.csv?raw'
14
+ import validHorizonData from './samples/valid-horizon-chart.json?raw'
15
+ import validMapData from './samples/valid-data-map.csv?raw'
16
+ import validMapDataFootnotes from './samples/valid-data-map-footnotes.csv?raw'
17
+ import validRadarData from './samples/valid-radar-chart.csv?raw'
17
18
  import validRegionData from './samples/valid-region-data.json?raw'
18
19
  import validSankeyData from './samples/valid-sankey-data.json?raw'
19
- import pivotData from './samples/pivotData.json?raw'
20
+ import validScatterPlot from './samples/valid-scatterplot.csv?raw'
21
+ import validWorldGeocodeData from './samples/valid-world-geocode.json?raw'
20
22
 
21
23
  // Convert visx cityTemperature data to CSV format
22
24
  const visxTemperatureData = (() => {
@@ -53,11 +55,21 @@ const sampleData = {
53
55
  fileName: 'valid-forecast-data.csv',
54
56
  data: validForecastData
55
57
  },
58
+ {
59
+ text: 'Horizon Chart Data',
60
+ fileName: 'valid-horizon-data.json',
61
+ data: validHorizonData
62
+ },
56
63
  {
57
64
  text: 'Sankey Chart Data',
58
65
  fileName: 'valid-sankey-data.json',
59
66
  data: validSankeyData
60
67
  },
68
+ {
69
+ text: 'Radar Chart Data (Program Comparison)',
70
+ fileName: 'valid-radar-chart.csv',
71
+ data: validRadarData
72
+ },
61
73
  {
62
74
  text: 'Pivot Table Data',
63
75
  fileName: 'pivotData.json',