@cdc/editor 4.22.10-alpha.1 → 4.22.11

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/README.md +8 -7
  2. package/dist/cdceditor.js +42 -42
  3. package/example/data-horizontal-filters.json +5 -6
  4. package/example/data-horizontal-multiseries-filters.json +13 -15
  5. package/example/data-horizontal-multiseries.json +4 -5
  6. package/example/data-horizontal.json +2 -3
  7. package/example/data-vertical-filters.json +7 -8
  8. package/example/data-vertical-multiseries-filters.json +13 -15
  9. package/example/data-vertical-multiseries-multirow-filters.json +49 -52
  10. package/example/data-vertical-multiseries-multirow.json +11 -11
  11. package/example/data-vertical-multiseries.json +4 -5
  12. package/example/data-vertical.json +4 -5
  13. package/example/private/city-state.json +434 -0
  14. package/example/private/example-city-state.json +86 -0
  15. package/example/private/map-issue.csv +11 -0
  16. package/example/private/test.html +26 -1
  17. package/example/region-map.json +32 -32
  18. package/example/valid-county-data.json +3047 -3047
  19. package/package.json +8 -8
  20. package/src/CdcEditor.js +72 -72
  21. package/src/components/ChooseTab.js +67 -88
  22. package/src/components/ConfigureTab.js +51 -51
  23. package/src/components/DataImport.js +248 -246
  24. package/src/components/PreviewDataTable.js +130 -149
  25. package/src/components/TabPane.js +3 -3
  26. package/src/components/Tabs.js +20 -27
  27. package/src/components/modal/Confirmation.js +16 -13
  28. package/src/components/modal/Modal.js +23 -35
  29. package/src/components/modal/UseModal.js +8 -8
  30. package/src/context.js +4 -4
  31. package/src/index.html +1 -4
  32. package/src/index.js +6 -7
  33. package/src/scss/_data-table.scss +1 -1
  34. package/src/scss/_variables.scss +1 -1
  35. package/src/scss/choose-vis-tab.scss +63 -63
  36. package/src/scss/configure-tab.scss +17 -17
  37. package/src/scss/data-import.scss +177 -177
  38. package/src/scss/main.scss +31 -32
@@ -16,7 +16,6 @@ import LinkIcon from '../assets/icons/link.svg'
16
16
  import FileUploadIcon from '../assets/icons/file-upload-solid.svg'
17
17
  import CloseIcon from '@cdc/core/assets/icon-close.svg'
18
18
 
19
-
20
19
  import validMapData from '../../example/valid-data-map.csv'
21
20
  import validChartData from '../../example/valid-data-chart.csv'
22
21
  import validCountyMapData from '../../example/valid-county-data.csv'
@@ -29,50 +28,39 @@ import '../scss/data-import.scss'
29
28
  import '@cdc/core/styles/v2/components/data-designer.scss'
30
29
 
31
30
  export default function DataImport() {
32
- const {
33
- config,
34
- setConfig,
35
- errors,
36
- setErrors,
37
- errorMessages,
38
- maxFileSize,
39
- setGlobalActive,
40
- tempConfig,
41
- setTempConfig,
42
- sharepath
43
- } = useContext(GlobalState)
31
+ const { config, setConfig, errors, setErrors, errorMessages, maxFileSize, setGlobalActive, tempConfig, setTempConfig, sharepath } = useContext(GlobalState)
44
32
 
45
33
  const { overlay } = useGlobalContext()
46
34
 
47
35
  const transform = new DataTransform()
48
36
 
49
- const [ externalURL, setExternalURL ] = useState(config.dataFileSourceType === 'url' ? config.dataFileName : (config.dataUrl || ''))
37
+ const [externalURL, setExternalURL] = useState(config.dataFileSourceType === 'url' ? config.dataFileName : config.dataUrl || '')
50
38
 
51
- const [ keepURL, setKeepURL ] = useState(!!config.dataUrl)
39
+ const [keepURL, setKeepURL] = useState(!!config.dataUrl)
52
40
 
53
- const [ addingDataset, setAddingDataset ] = useState(config.type === 'dashboard' || !config.data);
41
+ const [addingDataset, setAddingDataset] = useState(config.type === 'dashboard' || !config.data)
54
42
 
55
- const [ editingDataset, setEditingDataset ] = useState();
43
+ const [editingDataset, setEditingDataset] = useState()
56
44
 
57
45
  const supportedDataTypes = {
58
46
  '.csv': 'text/csv',
59
47
  '.json': 'application/json'
60
48
  }
61
49
 
62
- const displayFileName = (name) => {
63
- const nameParts = name.split('/');
64
- return nameParts[nameParts.length - 1];
50
+ const displayFileName = name => {
51
+ const nameParts = name.split('/')
52
+ return nameParts[nameParts.length - 1]
65
53
  }
66
54
 
67
- const displaySize = (size) => {
68
- if(size === undefined) return '';
55
+ const displaySize = size => {
56
+ if (size === undefined) return ''
69
57
 
70
- if(size > Math.pow(1024, 3)){
71
- return Math.round(size / Math.pow(1024, 3) * 100) / 100 + ' GB';
72
- } else if(size > Math.pow(1024, 2)){
73
- return Math.round(size / Math.pow(1024, 2) * 100) / 100 + ' MB';
74
- } else if(size > 1024){
75
- return Math.round(size / 1024 * 100) / 100 + ' KB';
58
+ if (size > Math.pow(1024, 3)) {
59
+ return Math.round((size / Math.pow(1024, 3)) * 100) / 100 + ' GB'
60
+ } else if (size > Math.pow(1024, 2)) {
61
+ return Math.round((size / Math.pow(1024, 2)) * 100) / 100 + ' MB'
62
+ } else if (size > 1024) {
63
+ return Math.round((size / 1024) * 100) / 100 + ' KB'
76
64
  } else {
77
65
  return size + ' B'
78
66
  }
@@ -82,16 +70,13 @@ export default function DataImport() {
82
70
  * Check to see all series for the viz exists in the new dataset
83
71
  */
84
72
  const dataExists = (newData, oldSeries, oldAxisX) => {
85
-
86
73
  // Loop through old series to make sure each exists in the new data
87
74
  oldSeries.map(function (currentValue, index, newData) {
88
- if (!newData.find(element => element.dataKey === currentValue.dataKey))
89
- return false
75
+ if (!newData.find(element => element.dataKey === currentValue.dataKey)) return false
90
76
  })
91
77
 
92
78
  // Is the X Axis still in the dataset?
93
- if (newData.columns.indexOf(oldAxisX) < 0)
94
- return false
79
+ if (newData.columns.indexOf(oldAxisX) < 0) return false
95
80
 
96
81
  return true
97
82
  }
@@ -109,20 +94,18 @@ export default function DataImport() {
109
94
  const fileExtension = Object.keys(supportedDataTypes).find(extension => dataURL.pathname.endsWith(extension))
110
95
 
111
96
  try {
112
- const response = await get(dataURL,
113
- {
114
- responseType: 'blob'
115
- })
116
- .then((response) => {
117
- responseBlob = response.data
118
-
119
- // Sometimes the files are coming in as plain text types... Maybe when saved from Macs
120
- if (fileExtension === '.csv' && responseBlob.type === 'text/plain') {
121
- responseBlob = responseBlob.slice(0, responseBlob.size, 'text/csv')
122
- } else if (fileExtension === '.json' && responseBlob.type === 'text/plain') {
123
- responseBlob = responseBlob.slice(0, responseBlob.size, 'application/json')
124
- }
125
- })
97
+ const response = await get(dataURL, {
98
+ responseType: 'blob'
99
+ }).then(response => {
100
+ responseBlob = response.data
101
+
102
+ // Sometimes the files are coming in as plain text types... Maybe when saved from Macs
103
+ if (fileExtension === '.csv' && responseBlob.type === 'text/plain') {
104
+ responseBlob = responseBlob.slice(0, responseBlob.size, 'text/csv')
105
+ } else if (fileExtension === '.json' && responseBlob.type === 'text/plain') {
106
+ responseBlob = responseBlob.slice(0, responseBlob.size, 'application/json')
107
+ }
108
+ })
126
109
  } catch (err) {
127
110
  console.error(err)
128
111
 
@@ -138,7 +121,7 @@ export default function DataImport() {
138
121
  return responseBlob
139
122
  }
140
123
 
141
- const onDrop = ([ uploadedFile ]) => loadData(uploadedFile, editingDataset, editingDataset)
124
+ const onDrop = ([uploadedFile]) => loadData(uploadedFile, editingDataset, editingDataset)
142
125
 
143
126
  /**
144
127
  * Handle loading data
@@ -155,24 +138,24 @@ export default function DataImport() {
155
138
  // const rounded = new Date(date.getTime() - (date.getTime() % round));
156
139
  // const trimmedDate = rounded.toString().replace(/\s+/g, "");
157
140
 
158
- const newUrl = new URL(fileName);
141
+ const newUrl = new URL(fileName)
159
142
  // newUrl.searchParams.append("v", trimmedDate);
160
143
 
161
- fileSourceType = "url";
144
+ fileSourceType = 'url'
162
145
  try {
163
146
  fileData = await loadExternal()
164
147
  fileSource = externalURL
165
148
  } catch (error) {
166
- setErrors([ error ])
149
+ setErrors([error])
167
150
  return
168
151
  }
169
152
  }
170
153
 
171
- let fileSize = fileData.size;
154
+ let fileSize = fileData.size
172
155
 
173
156
  // Check if file is too big
174
- if (fileSize > (maxFileSize * 1048576)) {
175
- setErrors([ errorMessages.fileTooLarge ])
157
+ if (fileSize > maxFileSize * 1048576) {
158
+ setErrors([errorMessages.fileTooLarge])
176
159
  return
177
160
  }
178
161
 
@@ -192,7 +175,7 @@ export default function DataImport() {
192
175
  let filereader = new FileReader()
193
176
 
194
177
  // Set encoding for CSV files - needed to render special characters properly
195
- let encoding = (mimeType === 'text/csv') ? 'ISO-8859-1' : ''
178
+ let encoding = mimeType === 'text/csv' ? 'ISO-8859-1' : ''
196
179
 
197
180
  filereader.onload = function () {
198
181
  let text = this.result
@@ -206,12 +189,12 @@ export default function DataImport() {
206
189
  try {
207
190
  text = JSON.parse(text)
208
191
  } catch (errors) {
209
- setErrors([ errorMessages.formatting ])
192
+ setErrors([errorMessages.formatting])
210
193
  return
211
194
  }
212
195
  break
213
196
  default:
214
- setErrors([ errorMessages.fileType ])
197
+ setErrors([errorMessages.fileType])
215
198
  return
216
199
  }
217
200
 
@@ -221,22 +204,22 @@ export default function DataImport() {
221
204
 
222
205
  if (config.data && config.series) {
223
206
  if (dataExists(text, config.series, config?.xAxis.dataKey)) {
224
- if(config.type === 'dashboard'){
225
- let newDatasets = {...config.datasets};
207
+ if (config.type === 'dashboard') {
208
+ let newDatasets = { ...config.datasets }
226
209
 
227
- Object.keys(newDatasets).forEach(datasetKey => newDatasets[datasetKey].preview = false);
210
+ Object.keys(newDatasets).forEach(datasetKey => (newDatasets[datasetKey].preview = false))
228
211
 
229
212
  newDatasets[editingDatasetKey || fileSource] = {
230
213
  data: text, // new data
231
214
  dataFileSize: fileSize,
232
215
  dataFileName: fileSource, // new file source
233
- dataFileSourceType: fileSourceType,// new file source type
216
+ dataFileSourceType: fileSourceType, // new file source type
234
217
  dataFileFormat: fileExtension.replace('.', '').toUpperCase(),
235
218
  preview: true
236
219
  }
237
220
 
238
- if(keepURL){
239
- newDatasets[editingDatasetKey || fileSource].dataUrl = fileSource;
221
+ if (keepURL) {
222
+ newDatasets[editingDatasetKey || fileSource].dataUrl = fileSource
240
223
  }
241
224
 
242
225
  setConfig({
@@ -253,35 +236,38 @@ export default function DataImport() {
253
236
  dataFileSourceType: fileSourceType, // new file source type
254
237
  formattedData: transform.developerStandardize(text, config.dataDescription)
255
238
  }
256
- if(keepURL){
257
- newConfig.dataUrl = fileSource;
239
+ if (keepURL) {
240
+ newConfig.dataUrl = fileSource
258
241
  }
259
242
  setConfig(newConfig)
260
243
  }
261
244
  } else {
262
- resetEditor({
263
- data: text,
264
- dataFileName: fileSource,
265
- dataFileSourceType: fileSourceType
266
- }, 'It appears that your data does not contain all of the columns that your last dataset contained. Continuing will reset your configuration. Do you want to continue?')
245
+ resetEditor(
246
+ {
247
+ data: text,
248
+ dataFileName: fileSource,
249
+ dataFileSourceType: fileSourceType
250
+ },
251
+ 'It appears that your data does not contain all of the columns that your last dataset contained. Continuing will reset your configuration. Do you want to continue?'
252
+ )
267
253
  }
268
254
  } else {
269
- if(config.type === 'dashboard') {
270
- let newDatasets = {...config.datasets};
255
+ if (config.type === 'dashboard') {
256
+ let newDatasets = { ...config.datasets }
271
257
 
272
- Object.keys(newDatasets).forEach(datasetKey => newDatasets[datasetKey].preview = false);
258
+ Object.keys(newDatasets).forEach(datasetKey => (newDatasets[datasetKey].preview = false))
273
259
 
274
260
  newDatasets[editingDatasetKey || fileSource] = {
275
261
  data: text, // new data
276
262
  dataFileSize: fileSize,
277
263
  dataFileName: fileSource, // new file source
278
- dataFileSourceType: fileSourceType,// new file source type
264
+ dataFileSourceType: fileSourceType, // new file source type
279
265
  dataFileFormat: fileExtension.replace('.', '').toUpperCase(),
280
266
  preview: true
281
267
  }
282
268
 
283
- if(keepURL){
284
- newDatasets[editingDatasetKey || fileSource].dataUrl = fileSource;
269
+ if (keepURL) {
270
+ newDatasets[editingDatasetKey || fileSource].dataUrl = fileSource
285
271
  }
286
272
 
287
273
  setConfig({ ...config, datasets: newDatasets })
@@ -292,25 +278,24 @@ export default function DataImport() {
292
278
  data: text, // new data
293
279
  dataFileName: fileSource, // new file source
294
280
  dataFileSourceType: fileSourceType, // new file source type
295
- formattedData: transform.developerStandardize(text, config.dataDescription)// new file source type
281
+ formattedData: transform.developerStandardize(text, config.dataDescription) // new file source type
296
282
  }
297
- if(keepURL){
298
- newConfig.dataUrl = fileSource;
283
+ if (keepURL) {
284
+ newConfig.dataUrl = fileSource
299
285
  }
300
286
  setConfig(newConfig)
301
287
  }
302
288
  }
303
289
 
304
- if(editingDataset){
305
- setEditingDataset(undefined);
290
+ if (editingDataset) {
291
+ setEditingDataset(undefined)
306
292
  }
307
- setAddingDataset(false);
308
- setExternalURL('');
309
- setKeepURL(false);
293
+ setAddingDataset(false)
294
+ setExternalURL('')
295
+ setKeepURL(false)
310
296
  } catch (err) {
311
297
  setErrors(err)
312
298
  }
313
-
314
299
  }
315
300
  filereader.readAsText(fileData, encoding)
316
301
  }
@@ -333,12 +318,12 @@ export default function DataImport() {
333
318
  }, [])
334
319
 
335
320
  const updateDescriptionProp = (visualizationKey, datasetKey, key, value) => {
336
- if(config.type === 'dashboard') {
321
+ if (config.type === 'dashboard') {
337
322
  let dataDescription = { ...config.datasets[datasetKey].dataDescription, [key]: value }
338
323
  let formattedData = transform.developerStandardize(config.datasets[datasetKey].data, dataDescription)
339
324
 
340
- let newDatasets = {...config.datasets}
341
- newDatasets[datasetKey] = {...newDatasets[datasetKey], dataDescription, formattedData};
325
+ let newDatasets = { ...config.datasets }
326
+ newDatasets[datasetKey] = { ...newDatasets[datasetKey], dataDescription, formattedData }
342
327
 
343
328
  setConfig({ ...config, datasets: newDatasets })
344
329
  } else {
@@ -350,25 +335,25 @@ export default function DataImport() {
350
335
  }
351
336
 
352
337
  const changeKeepURL = (value, editingDatasetKey) => {
353
- if(editingDatasetKey){
354
- let newDatasets = {...config.datasets};
355
- if(value === false){
356
- delete newDatasets[editingDatasetKey].dataUrl;
338
+ if (editingDatasetKey) {
339
+ let newDatasets = { ...config.datasets }
340
+ if (value === false) {
341
+ delete newDatasets[editingDatasetKey].dataUrl
357
342
  } else {
358
- newDatasets[editingDatasetKey].dataUrl = newDatasets[editingDatasetKey].dataFileName;
343
+ newDatasets[editingDatasetKey].dataUrl = newDatasets[editingDatasetKey].dataFileName
359
344
  }
360
- setConfig({...config, datasets: newDatasets});
361
- } else if(config.type !== 'dashboard') {
362
- let newConfig = {...config};
363
- if(value === false){
364
- delete newConfig.dataUrl;
345
+ setConfig({ ...config, datasets: newDatasets })
346
+ } else if (config.type !== 'dashboard') {
347
+ let newConfig = { ...config }
348
+ if (value === false) {
349
+ delete newConfig.dataUrl
365
350
  } else {
366
- newConfig.dataUrl = newConfig.dataFileName;
351
+ newConfig.dataUrl = newConfig.dataFileName
367
352
  }
368
- setConfig(newConfig);
353
+ setConfig(newConfig)
369
354
  }
370
- setKeepURL(value);
371
- };
355
+ setKeepURL(value)
356
+ }
372
357
 
373
358
  const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop })
374
359
  const { getRootProps: getRootProps2, getInputProps: getInputProps2, isDragActive: isDragActive2 } = useDropzone({ onDrop })
@@ -378,17 +363,14 @@ export default function DataImport() {
378
363
 
379
364
  return (
380
365
  <>
381
- <form className="input-group d-flex" onSubmit={(e) => e.preventDefault()}>
382
- <input id="external-data" type="text" className="form-control flex-grow-1 border-right-0"
383
- placeholder="e.g., https://data.cdc.gov/resources/file.json" aria-label="Load data from external URL"
384
- aria-describedby="load-data" value={externalURL} onChange={(e) => setExternalURL(e.target.value)}/>
385
- <button className="input-group-text btn btn-primary px-4" type="submit" id="load-data"
386
- onClick={() => loadData(null, externalURL, editingDatasetKey)}>Load
366
+ <form className='input-group d-flex' onSubmit={e => e.preventDefault()}>
367
+ <input id='external-data' type='text' className='form-control flex-grow-1 border-right-0' placeholder='e.g., https://data.cdc.gov/resources/file.json' aria-label='Load data from external URL' aria-describedby='load-data' value={externalURL} onChange={e => setExternalURL(e.target.value)} />
368
+ <button className='input-group-text btn btn-primary px-4' type='submit' id='load-data' onClick={() => loadData(null, externalURL, editingDatasetKey)}>
369
+ Load
387
370
  </button>
388
371
  </form>
389
- <label htmlFor="keep-url" className="mt-1 d-flex keep-url">
390
- <input type="checkbox" id="keep-url" checked={keepURL} onChange={() => changeKeepURL(!keepURL, editingDatasetKey)}/> Always
391
- load from URL (normally will only pull once)
372
+ <label htmlFor='keep-url' className='mt-1 d-flex keep-url'>
373
+ <input type='checkbox' id='keep-url' checked={keepURL} onChange={() => changeKeepURL(!keepURL, editingDatasetKey)} /> Always load from URL (normally will only pull once)
392
374
  </label>
393
375
  </>
394
376
  )
@@ -407,119 +389,145 @@ export default function DataImport() {
407
389
  }
408
390
 
409
391
  const resetButton = () => {
410
- return ( //todo convert to modal
411
- <button className="btn danger"
412
- onClick={() => resetEditor({type: config.type, visualizationType: config.visualizationType}, 'Reseting will remove your data and settings. Do you want to continue?')}>Clear
413
- <CloseIcon/>
392
+ return (
393
+ //todo convert to modal
394
+ <button className='btn danger' onClick={() => resetEditor({ type: config.type, visualizationType: config.visualizationType }, 'Reseting will remove your data and settings. Do you want to continue?')}>
395
+ Clear
396
+ <CloseIcon />
414
397
  </button>
415
398
  )
416
399
  }
417
400
 
418
401
  const setGlobalDatasetProp = (datasetKey, prop, value) => {
419
- let newDatasets = {...config.datasets};
402
+ let newDatasets = { ...config.datasets }
420
403
 
421
- if(value === true){
404
+ if (value === true) {
422
405
  Object.keys(newDatasets).forEach(datasetKeyIter => {
423
- if(datasetKeyIter !== datasetKey){
424
- newDatasets[datasetKeyIter][prop] = false;
406
+ if (datasetKeyIter !== datasetKey) {
407
+ newDatasets[datasetKeyIter][prop] = false
425
408
  } else {
426
- newDatasets[datasetKeyIter][prop] = true;
409
+ newDatasets[datasetKeyIter][prop] = true
427
410
  }
428
411
  })
429
412
  } else {
430
- newDatasets[datasetKey][prop] = value;
413
+ newDatasets[datasetKey][prop] = value
431
414
  }
432
415
 
433
- setConfig({...config, datasets: newDatasets});
434
- };
416
+ setConfig({ ...config, datasets: newDatasets })
417
+ }
435
418
 
436
- const removeDataset = (datasetKey) => {
437
- let newDatasets = {...config.datasets};
438
- let newVisualizations = {...config.visualizations};
419
+ const removeDataset = datasetKey => {
420
+ let newDatasets = { ...config.datasets }
421
+ let newVisualizations = { ...config.visualizations }
439
422
 
440
423
  Object.keys(newVisualizations).forEach(vizKey => {
441
- if(newVisualizations[vizKey].dataKey === datasetKey) {
442
- delete newVisualizations[vizKey].dataKey;
424
+ if (newVisualizations[vizKey].dataKey === datasetKey) {
425
+ delete newVisualizations[vizKey].dataKey
443
426
  }
444
- });
427
+ })
445
428
 
446
- delete newDatasets[datasetKey];
429
+ delete newDatasets[datasetKey]
447
430
 
448
- setConfig({...config, datasets: newDatasets, visualizations: newVisualizations});
431
+ setConfig({ ...config, datasets: newDatasets, visualizations: newVisualizations })
449
432
  }
450
433
 
451
434
  const renameDataset = (oldName, newName) => {
452
- if(oldName === newName) return;
435
+ if (oldName === newName) return
453
436
 
454
- let newDatasets = {...config.datasets};
455
- let newVisualizations = {...config.visualizations};
437
+ let newDatasets = { ...config.datasets }
438
+ let newVisualizations = { ...config.visualizations }
456
439
 
457
- let suffix = 2;
458
- let originalName = newName;
459
- while(newDatasets[newName]){
460
- newName = originalName + '-' + suffix;
461
- suffix++;
440
+ let suffix = 2
441
+ let originalName = newName
442
+ while (newDatasets[newName]) {
443
+ newName = originalName + '-' + suffix
444
+ suffix++
462
445
  }
463
446
 
464
- newDatasets[newName] = newDatasets[oldName];
465
- delete newDatasets[oldName];
447
+ newDatasets[newName] = newDatasets[oldName]
448
+ delete newDatasets[oldName]
466
449
 
467
450
  Object.keys(newVisualizations).forEach(vizKey => {
468
- if(newVisualizations[vizKey].dataKey === oldName) {
469
- newVisualizations[vizKey].dataKey = newName;
451
+ if (newVisualizations[vizKey].dataKey === oldName) {
452
+ newVisualizations[vizKey].dataKey = newName
470
453
  }
471
- });
454
+ })
472
455
 
473
- setConfig({...config, datasets: newDatasets, visualizations: newVisualizations});
456
+ setConfig({ ...config, datasets: newDatasets, visualizations: newVisualizations })
474
457
  }
475
458
 
476
- let previewData, configureData, readyToConfigure = false;
477
- if(config.type === 'dashboard'){
478
- readyToConfigure = Object.keys(config.datasets).length > 0;
459
+ let previewData,
460
+ configureData,
461
+ readyToConfigure = false
462
+ if (config.type === 'dashboard') {
463
+ readyToConfigure = Object.keys(config.datasets).length > 0
479
464
  Object.keys(config.datasets).forEach(datasetKey => {
480
- if(config.datasets[datasetKey].preview){
481
- previewData = config.datasets[datasetKey].data;
465
+ if (config.datasets[datasetKey].preview) {
466
+ previewData = config.datasets[datasetKey].data
482
467
  }
483
- });
468
+ })
484
469
  } else {
485
- previewData = config.data;
486
- configureData = config;
487
- readyToConfigure = !!config.formattedData;
470
+ previewData = config.data
471
+ configureData = config
472
+ readyToConfigure = !!config.formattedData
488
473
  }
489
474
 
490
475
  return (
491
476
  <>
492
- <div className="left-col">
477
+ <div className='left-col'>
493
478
  {config.type === 'dashboard' && Object.keys(config.datasets).length > 0 && (
494
479
  <>
495
- <div className="heading-3">Data Sources</div>
480
+ <div className='heading-3'>Data Sources</div>
496
481
  <table>
497
482
  <thead>
498
483
  <tr>
499
- <th>Name</th><th>Size</th><th>Type</th><th colSpan="4">Actions</th>
484
+ <th>Name</th>
485
+ <th>Size</th>
486
+ <th>Type</th>
487
+ <th colSpan='4'>Actions</th>
500
488
  </tr>
501
489
  </thead>
502
490
  <tbody>
503
- {Object.keys(config.datasets).map(datasetKey => config.datasets[datasetKey].dataFileName && (
504
- <tr key={`tr-${datasetKey}`}>
505
- <td><input className="dataset-name-input" type="text" defaultValue={datasetKey} onBlur={(e) => renameDataset(datasetKey, e.target.value)}/></td>
506
- <td>{displaySize(config.datasets[datasetKey].dataFileSize)}</td>
507
- <td>{config.datasets[datasetKey].dataFileFormat}</td>
508
- <td><button className="btn btn-primary" onClick={() => setGlobalDatasetProp(datasetKey, 'preview', true)}>Preview Data</button></td>
509
- <td><button className="btn btn-primary" onClick={() => {
510
- if(editingDataset === datasetKey){
511
- setEditingDataset(undefined);
512
- setExternalURL('');
513
- setKeepURL(false);
514
- } else {
515
- setEditingDataset(datasetKey);
516
- setExternalURL(config.datasets[datasetKey].dataUrl || config.datasets[datasetKey].dataFileName);
517
- setKeepURL(!!config.datasets[datasetKey].dataUrl);
518
- }
519
- }}>Edit Data</button></td>
520
- <td><button className="btn btn-primary" onClick={() => removeDataset(datasetKey)}>X</button></td>
521
- </tr>
522
- ))}
491
+ {Object.keys(config.datasets).map(
492
+ datasetKey =>
493
+ config.datasets[datasetKey].dataFileName && (
494
+ <tr key={`tr-${datasetKey}`}>
495
+ <td>
496
+ <input className='dataset-name-input' type='text' defaultValue={datasetKey} onBlur={e => renameDataset(datasetKey, e.target.value)} />
497
+ </td>
498
+ <td>{displaySize(config.datasets[datasetKey].dataFileSize)}</td>
499
+ <td>{config.datasets[datasetKey].dataFileFormat}</td>
500
+ <td>
501
+ <button className='btn btn-primary' onClick={() => setGlobalDatasetProp(datasetKey, 'preview', true)}>
502
+ Preview Data
503
+ </button>
504
+ </td>
505
+ <td>
506
+ <button
507
+ className='btn btn-primary'
508
+ onClick={() => {
509
+ if (editingDataset === datasetKey) {
510
+ setEditingDataset(undefined)
511
+ setExternalURL('')
512
+ setKeepURL(false)
513
+ } else {
514
+ setEditingDataset(datasetKey)
515
+ setExternalURL(config.datasets[datasetKey].dataUrl || config.datasets[datasetKey].dataFileName)
516
+ setKeepURL(!!config.datasets[datasetKey].dataUrl)
517
+ }
518
+ }}
519
+ >
520
+ Edit Data
521
+ </button>
522
+ </td>
523
+ <td>
524
+ <button className='btn btn-primary' onClick={() => removeDataset(datasetKey)}>
525
+ X
526
+ </button>
527
+ </td>
528
+ </tr>
529
+ )
530
+ )}
523
531
  </tbody>
524
532
  </table>
525
533
  </>
@@ -529,33 +537,28 @@ export default function DataImport() {
529
537
  <>
530
538
  {config.type !== 'dashboard' && (
531
539
  <>
532
- <div className="heading-3">Data Source</div>
533
- <div className="file-loaded-area">
540
+ <div className='heading-3'>Data Source</div>
541
+ <div className='file-loaded-area'>
534
542
  {config.dataFileSourceType === 'file' && (
535
- <div className="data-source-options">
536
- <div
537
- className={isDragActive2 ? 'drag-active cdcdataviz-file-selector loaded-file' : 'cdcdataviz-file-selector loaded-file'} {...getRootProps2()}>
543
+ <div className='data-source-options'>
544
+ <div className={isDragActive2 ? 'drag-active cdcdataviz-file-selector loaded-file' : 'cdcdataviz-file-selector loaded-file'} {...getRootProps2()}>
538
545
  <input {...getInputProps2()} />
539
- {
540
- isDragActive2 ?
541
- <p>Drop file here</p> :
542
- <p><FileUploadIcon/> <span>{config.dataFileName ?? 'Replace data file'}</span></p>
543
- }
544
- </div>
545
- <div>
546
- {resetButton()}
546
+ {isDragActive2 ? (
547
+ <p>Drop file here</p>
548
+ ) : (
549
+ <p>
550
+ <FileUploadIcon /> <span>{config.dataFileName ?? 'Replace data file'}</span>
551
+ </p>
552
+ )}
547
553
  </div>
554
+ <div>{resetButton()}</div>
548
555
  </div>
549
556
  )}
550
557
 
551
558
  {config.dataFileSourceType === 'url' && (
552
- <div className="url-source-options">
553
- <div>
554
- {loadFileFromUrl(externalURL)}
555
- </div>
556
- <div>
557
- {resetButton()}
558
- </div>
559
+ <div className='url-source-options'>
560
+ <div>{loadFileFromUrl(externalURL)}</div>
561
+ <div>{resetButton()}</div>
559
562
  </div>
560
563
  )}
561
564
  </div>
@@ -566,75 +569,74 @@ export default function DataImport() {
566
569
  </>
567
570
  )}
568
571
 
569
- {(editingDataset || addingDataset) && ( // dataFileSourceType needs to be checked here since earlier versions did not track this state
570
- <div className="load-data-area">
571
- <div className="heading-3">{editingDataset ? `Editing ${editingDataset}` : 'Add Dataset'}</div>
572
+ {(editingDataset || addingDataset) && ( // dataFileSourceType needs to be checked here since earlier versions did not track this state
573
+ <div className='load-data-area'>
574
+ <div className='heading-3'>{editingDataset ? `Editing ${editingDataset}` : 'Add Dataset'}</div>
572
575
  <Tabs startingTab={editingDataset && config.datasets[editingDataset].dataFileSourceType === 'url' ? 1 : 0}>
573
- <TabPane title="Upload File" icon={<FileUploadIcon className="inline-icon"/>}>
574
- {sharepath &&
575
- <p className="alert--info">
576
- The share path set for this website is: {sharepath}
577
- </p>
578
- }
579
- <div
580
- className={isDragActive ? 'drag-active cdcdataviz-file-selector' : 'cdcdataviz-file-selector'} {...getRootProps()}>
576
+ <TabPane title='Upload File' icon={<FileUploadIcon className='inline-icon' />}>
577
+ {sharepath && <p className='alert--info'>The share path set for this website is: {sharepath}</p>}
578
+ <div className={isDragActive ? 'drag-active cdcdataviz-file-selector' : 'cdcdataviz-file-selector'} {...getRootProps()}>
581
579
  <input {...getInputProps()} />
582
- {
583
- isDragActive ?
584
- <p>Drop file here</p> :
585
- <p>Drag file to this area, or <span>select a file</span>.</p>
586
- }
580
+ {isDragActive ? (
581
+ <p>Drop file here</p>
582
+ ) : (
583
+ <p>
584
+ Drag file to this area, or <span>select a file</span>.
585
+ </p>
586
+ )}
587
587
  </div>
588
588
  </TabPane>
589
- <TabPane title="Load from URL" icon={<LinkIcon className="inline-icon"/>}>
589
+ <TabPane title='Load from URL' icon={<LinkIcon className='inline-icon' />}>
590
590
  {loadFileFromUrl(editingDataset && config.datasets[editingDataset].dataFileSourceType === 'url' ? config.datasets[editingDataset].dataFileName : externalURL, editingDataset)}
591
591
  </TabPane>
592
592
  </Tabs>
593
- {errors && (errors.map ? errors.map((message, index) => (
594
- <div className="error-box slim mt-2" key={`error-${message}`}>
595
- <span>{message}</span> <CloseIcon className="inline-icon dismiss-error"
596
- onClick={() => setErrors(errors.filter((val, i) => i !== index))}/>
597
- </div>
598
- )) : errors.message)}
599
- <p className="footnote">Supported file types: {Object.keys(supportedDataTypes).join(', ')}. Maximum file
600
- size {maxFileSize}MB.</p>
593
+ {errors &&
594
+ (errors.map
595
+ ? errors.map((message, index) => (
596
+ <div className='error-box slim mt-2' key={`error-${message}`}>
597
+ <span>{message}</span> <CloseIcon className='inline-icon dismiss-error' onClick={() => setErrors(errors.filter((val, i) => i !== index))} />
598
+ </div>
599
+ ))
600
+ : errors.message)}
601
+ <p className='footnote'>
602
+ Supported file types: {Object.keys(supportedDataTypes).join(', ')}. Maximum file size {maxFileSize}MB.
603
+ </p>
601
604
  {/* TODO: Add more sample data in, but this will do for now. */}
602
- <span className="heading-3">Load Sample Data:</span>
603
- <ul className="sample-data-list">
604
- <li
605
- onClick={() => loadData(new Blob([ validMapData ], { type: 'text/csv' }), 'valid-data-map.csv', editingDataset)}>United
606
- States Sample Data #1
607
- </li>
608
- <li
609
- onClick={() => loadData(new Blob([ validChartData ], { type: 'text/csv' }), 'valid-data-chart.csv', editingDataset)}>Chart
610
- Sample Data
611
- </li>
612
- <li
613
- onClick={() => loadData(new Blob([ validCountyMapData ], { type: 'text/csv' }), 'valid-county-data.csv', editingDataset)}>United
614
- States Counties Sample Data
615
- </li>
616
- <li
617
- onClick={() => loadData(new Blob([ sampleGeoPoints ], { type: 'text/csv' }), 'supported-cities.csv', editingDataset)}>
618
- Sample Geo Points
619
- </li>
605
+ <span className='heading-3'>Load Sample Data:</span>
606
+ <ul className='sample-data-list'>
607
+ <li onClick={() => loadData(new Blob([validMapData], { type: 'text/csv' }), 'valid-data-map.csv', editingDataset)}>United States Sample Data #1</li>
608
+ <li onClick={() => loadData(new Blob([validChartData], { type: 'text/csv' }), 'valid-data-chart.csv', editingDataset)}>Chart Sample Data</li>
609
+ <li onClick={() => loadData(new Blob([validCountyMapData], { type: 'text/csv' }), 'valid-county-data.csv', editingDataset)}>United States Counties Sample Data</li>
610
+ <li onClick={() => loadData(new Blob([sampleGeoPoints], { type: 'text/csv' }), 'supported-cities.csv', editingDataset)}>Sample Geo Points</li>
620
611
  </ul>
621
612
  </div>
622
613
  )}
623
614
 
624
- {config.type === 'dashboard' && !addingDataset && <p><button className="btn btn-primary" onClick={() => setAddingDataset(true)}>+ Add More Files</button></p>}
615
+ {config.type === 'dashboard' && !addingDataset && (
616
+ <p>
617
+ <button className='btn btn-primary' onClick={() => setAddingDataset(true)}>
618
+ + Add More Files
619
+ </button>
620
+ </p>
621
+ )}
625
622
 
626
- {readyToConfigure && <p><button className="btn btn-primary" onClick={() => setGlobalActive(2)}>Configure your visualization</button></p>}
623
+ {readyToConfigure && (
624
+ <p>
625
+ <button className='btn btn-primary' onClick={() => setGlobalActive(2)}>
626
+ Configure your visualization
627
+ </button>
628
+ </p>
629
+ )}
627
630
 
628
- <a href="https://www.cdc.gov/wcms/4.0/cdc-wp/data-presentation/data-map.html" target="_blank"
629
- rel="noopener noreferrer" className="guidance-link">
631
+ <a href='https://www.cdc.gov/wcms/4.0/cdc-wp/data-presentation/data-map.html' target='_blank' rel='noopener noreferrer' className='guidance-link'>
630
632
  <div>
631
633
  <h3>Get Help</h3>
632
634
  <p>Documentation and examples on formatting data and configuring visualizations.</p>
633
635
  </div>
634
636
  </a>
635
637
  </div>
636
- <div className="right-col">
637
- <PreviewDataTable data={previewData}/>
638
+ <div className='right-col'>
639
+ <PreviewDataTable data={previewData} />
638
640
  </div>
639
641
  </>
640
642
  )