@cdc/chart 4.22.10 → 4.23.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 (80) hide show
  1. package/README.md +5 -5
  2. package/dist/495.js +3 -0
  3. package/dist/703.js +1 -0
  4. package/dist/cdcchart.js +723 -6
  5. package/examples/age-adjusted-rates.json +1486 -1218
  6. package/examples/box-plot-data.json +71 -0
  7. package/examples/box-plot.csv +5 -0
  8. package/examples/{private/yaxis-test.json → box-plot.json} +46 -54
  9. package/examples/case-rate-example-config.json +1 -1
  10. package/examples/covid-confidence-example-config.json +33 -33
  11. package/examples/covid-example-config.json +34 -34
  12. package/examples/covid-example-data-confidence.json +30 -30
  13. package/examples/covid-example-data.json +20 -20
  14. package/examples/cutoff-example-config.json +36 -36
  15. package/examples/cutoff-example-data.json +36 -36
  16. package/examples/date-exclusions-config.json +1 -1
  17. package/examples/dynamic-legends.json +124 -124
  18. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart-with-numbers-on-bar.json +191 -197
  19. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart.json +230 -240
  20. package/examples/gallery/bar-chart-horizontal/horizontal-stacked.json +239 -247
  21. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +138 -136
  22. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +79 -79
  23. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +80 -80
  24. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-with-confidence.json +67 -67
  25. package/examples/gallery/bar-chart-vertical/vertical-bar-chart.json +179 -110
  26. package/examples/gallery/lollipop/lollipop-style-horizontal.json +215 -219
  27. package/examples/gallery/paired-bar/paired-bar-chart.json +195 -195
  28. package/examples/horizontal-chart.json +35 -35
  29. package/examples/horizontal-stacked-bar-chart.json +34 -34
  30. package/examples/line-chart.json +75 -75
  31. package/examples/new-data.csv +17 -0
  32. package/examples/newdata.json +90 -0
  33. package/examples/paired-bar-data.json +16 -14
  34. package/examples/paired-bar-example.json +48 -48
  35. package/examples/paired-bar-formatted.json +36 -36
  36. package/examples/planet-chart-horizontal-example-config.json +33 -33
  37. package/examples/planet-combo-example-config.json +34 -31
  38. package/examples/planet-example-config.json +35 -33
  39. package/examples/planet-example-data.json +56 -56
  40. package/examples/planet-pie-example-config.json +28 -28
  41. package/examples/stacked-vertical-bar-example.json +1 -1
  42. package/examples/temp-example-config.json +61 -54
  43. package/examples/temp-example-data.json +1 -1
  44. package/package.json +3 -2
  45. package/src/CdcChart.tsx +449 -434
  46. package/src/components/BarChart.tsx +383 -497
  47. package/src/components/BoxPlot.js +92 -0
  48. package/src/components/DataTable.tsx +182 -197
  49. package/src/components/EditorPanel.js +1068 -722
  50. package/src/components/Filters.js +131 -0
  51. package/src/components/Legend.js +286 -329
  52. package/src/components/LineChart.tsx +143 -81
  53. package/src/components/LinearChart.tsx +432 -451
  54. package/src/components/PairedBarChart.tsx +197 -213
  55. package/src/components/PieChart.tsx +105 -151
  56. package/src/components/SparkLine.js +179 -201
  57. package/src/components/useIntersectionObserver.tsx +19 -20
  58. package/src/context.tsx +3 -3
  59. package/src/data/initial-state.js +44 -17
  60. package/src/hooks/useActiveElement.js +13 -13
  61. package/src/hooks/useChartClasses.js +34 -28
  62. package/src/hooks/useColorPalette.ts +56 -63
  63. package/src/hooks/useLegendClasses.js +18 -10
  64. package/src/hooks/useReduceData.ts +64 -77
  65. package/src/hooks/useRightAxis.js +25 -0
  66. package/src/hooks/useTopAxis.js +6 -0
  67. package/src/index.html +19 -19
  68. package/src/index.tsx +13 -16
  69. package/src/scss/DataTable.scss +6 -5
  70. package/src/scss/editor-panel.scss +71 -69
  71. package/src/scss/main.scss +188 -114
  72. package/src/scss/variables.scss +1 -1
  73. package/examples/private/line-test-data.json +0 -22
  74. package/examples/private/line-test-two.json +0 -216
  75. package/examples/private/line-test.json +0 -102
  76. package/examples/private/newtest.csv +0 -101
  77. package/examples/private/shawn.json +0 -1296
  78. package/examples/private/test.json +0 -10124
  79. package/examples/private/yaxis-testing.csv +0 -27
  80. package/examples/private/yaxis.json +0 -28
@@ -1,46 +1,42 @@
1
1
  import React, { useState, useEffect, useCallback, memo, useContext } from 'react'
2
2
  import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'
3
3
 
4
- import {
5
- Accordion,
6
- AccordionItem,
7
- AccordionItemHeading,
8
- AccordionItemPanel,
9
- AccordionItemButton,
10
- } from 'react-accessible-accordion'
4
+ import { Accordion, AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
11
5
 
12
- import { timeParse, timeFormat } from 'd3-time-format'
13
- import { useDebounce, useDebouncedCallback } from 'use-debounce'
6
+ import { useDebounce } from 'use-debounce'
14
7
 
15
8
  import Context from '../context'
16
9
  import WarningImage from '../images/warning.svg'
17
- import AdvancedEditor from '@cdc/core/components/AdvancedEditor';
10
+ import AdvancedEditor from '@cdc/core/components/AdvancedEditor'
18
11
 
19
- import ErrorBoundary from '@cdc/core/components/ErrorBoundary';
20
- import Waiting from '@cdc/core/components/Waiting';
21
- import QuestionIcon from '@cdc/core/assets/icon-question-circle.svg'; //TODO: Update with Icon component
22
- import {useColorPalette} from '../hooks/useColorPalette';
12
+ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
13
+ import { useColorPalette } from '../hooks/useColorPalette'
23
14
 
24
- import InputCheckbox from '@cdc/core/components/inputs/InputCheckbox';
25
- import InputToggle from '@cdc/core/components/inputs/InputToggle';
15
+ import InputToggle from '@cdc/core/components/inputs/InputToggle'
26
16
  import Tooltip from '@cdc/core/components/ui/Tooltip'
27
17
  import Icon from '@cdc/core/components/ui/Icon'
28
- import useReduceData from '../hooks/useReduceData';
18
+ import useReduceData from '../hooks/useReduceData'
19
+ import useRightAxis from '../hooks/useRightAxis'
29
20
 
30
- const TextField = memo(({label, tooltip, section = null, subsection = null, fieldName, updateField, value: stateValue, type = "input", i = null, min = null, ...attributes}) => {
31
- const [ value, setValue ] = useState(stateValue);
21
+ // TODO: Remove unused imports
22
+ // TDOO: Move inline styles to a scss file
32
23
 
33
- const [ debouncedValue ] = useDebounce(value, 500);
24
+ /* eslint-disable react-hooks/rules-of-hooks */
25
+
26
+ const TextField = memo(({ label, tooltip, section = null, subsection = null, fieldName, updateField, value: stateValue, type = 'input', i = null, min = null, ...attributes }) => {
27
+ const [value, setValue] = useState(stateValue)
28
+
29
+ const [debouncedValue] = useDebounce(value, 500)
34
30
 
35
31
  useEffect(() => {
36
32
  if ('string' === typeof debouncedValue && stateValue !== debouncedValue) {
37
33
  updateField(section, subsection, fieldName, debouncedValue, i)
38
34
  }
39
- }, [ debouncedValue ])
35
+ }, [debouncedValue]) // eslint-disable-line
40
36
 
41
37
  let name = subsection ? `${section}-${subsection}-${fieldName}` : `${section}-${subsection}-${fieldName}`
42
38
 
43
- const onChange = (e) => {
39
+ const onChange = e => {
44
40
  if ('number' !== type || min === null) {
45
41
  setValue(e.target.value)
46
42
  } else {
@@ -52,52 +48,79 @@ const TextField = memo(({label, tooltip, section = null, subsection = null, fiel
52
48
  }
53
49
  }
54
50
 
55
- let formElement = <input type="text" name={name} onChange={onChange} {...attributes} value={value}/>
51
+ let formElement = <input type='text' name={name} onChange={onChange} {...attributes} value={value} />
56
52
 
57
53
  if ('textarea' === type) {
58
- formElement = (
59
- <textarea name={name} onChange={onChange} {...attributes} value={value}></textarea>
60
- )
54
+ formElement = <textarea name={name} onChange={onChange} {...attributes} value={value}></textarea>
61
55
  }
62
56
 
63
57
  if ('number' === type) {
64
- formElement = <input type="number" name={name} onChange={onChange} {...attributes} value={value}/>
58
+ formElement = <input type='number' name={name} onChange={onChange} {...attributes} value={value} />
65
59
  }
66
60
 
67
61
  if ('date' === type) {
68
- formElement = <input type="date" name={name} onChange={onChange} {...attributes} value={value}/>
62
+ formElement = <input type='date' name={name} onChange={onChange} {...attributes} value={value} />
69
63
  }
70
64
 
71
65
  return (
72
66
  <label>
73
- <span className="edit-label column-heading">{label}{tooltip}</span>
67
+ <span className='edit-label column-heading'>
68
+ {label}
69
+ {tooltip}
70
+ </span>
74
71
  {formElement}
75
72
  </label>
76
73
  )
77
74
  })
78
75
 
79
76
  const CheckBox = memo(({ label, value, fieldName, section = null, subsection = null, tooltip, updateField, ...attributes }) => (
80
- <label className="checkbox">
81
- <input type="checkbox" name={fieldName} checked={value} onChange={() => {
82
- updateField(section, subsection, fieldName, !value)
83
- }} {...attributes}/>
84
- <span className="edit-label">{label}{tooltip}</span>
77
+ <label className='checkbox'>
78
+ <input
79
+ type='checkbox'
80
+ name={fieldName}
81
+ checked={value}
82
+ onChange={() => {
83
+ updateField(section, subsection, fieldName, !value)
84
+ }}
85
+ {...attributes}
86
+ />
87
+ <span className='edit-label'>
88
+ {label}
89
+ {tooltip}
90
+ </span>
85
91
  </label>
86
92
  ))
87
93
 
88
94
  const Select = memo(({ label, value, options, fieldName, section = null, subsection = null, required = false, tooltip, updateField, initial: initialValue, ...attributes }) => {
89
- let optionsJsx = options.map((optionName, index) => <option value={optionName} key={index}>{optionName}</option>)
95
+ let optionsJsx = options.map((optionName, index) => (
96
+ <option value={optionName} key={index}>
97
+ {optionName}
98
+ </option>
99
+ ))
90
100
 
91
101
  if (initialValue) {
92
- optionsJsx.unshift(<option value="" key="initial">{initialValue}</option>)
102
+ optionsJsx.unshift(
103
+ <option value='' key='initial'>
104
+ {initialValue}
105
+ </option>
106
+ )
93
107
  }
94
108
 
95
109
  return (
96
110
  <label>
97
- <span className="edit-label">{label}{tooltip}</span>
98
- <select className={required && !value ? 'warning' : ''} name={fieldName} value={value} onChange={(event) => {
99
- updateField(section, subsection, fieldName, event.target.value)
100
- }} {...attributes}>
111
+ <span className='edit-label'>
112
+ {label}
113
+ {tooltip}
114
+ </span>
115
+ <select
116
+ className={required && !value ? 'warning' : ''}
117
+ name={fieldName}
118
+ value={value}
119
+ onChange={event => {
120
+ updateField(section, subsection, fieldName, event.target.value)
121
+ }}
122
+ {...attributes}
123
+ >
101
124
  {optionsJsx}
102
125
  </select>
103
126
  </label>
@@ -109,7 +132,7 @@ const Regions = memo(({ config, updateConfig }) => {
109
132
  let regions = []
110
133
 
111
134
  if (config.regions) {
112
- regions = [ ...config.regions ]
135
+ regions = [...config.regions]
113
136
  }
114
137
 
115
138
  regions[i][fieldName] = value
@@ -118,11 +141,11 @@ const Regions = memo(({ config, updateConfig }) => {
118
141
 
119
142
  let updateField = (section, subsection, fieldName, value, i) => regionUpdate(fieldName, value, i)
120
143
 
121
- let removeColumn = (i) => {
144
+ let removeColumn = i => {
122
145
  let regions = []
123
146
 
124
147
  if (config.regions) {
125
- regions = [ ...config.regions ]
148
+ regions = [...config.regions]
126
149
  }
127
150
 
128
151
  regions.splice(i, 1)
@@ -131,11 +154,10 @@ const Regions = memo(({ config, updateConfig }) => {
131
154
  }
132
155
 
133
156
  let addColumn = () => {
134
-
135
157
  let regions = []
136
158
 
137
159
  if (config.regions) {
138
- regions = [ ...config.regions ]
160
+ regions = [...config.regions]
139
161
  }
140
162
 
141
163
  regions.push({})
@@ -145,63 +167,83 @@ const Regions = memo(({ config, updateConfig }) => {
145
167
 
146
168
  return (
147
169
  <>
148
- {config.regions && config.regions.map(({ label, color, from, to, background }, i) => (
149
- <div className="edit-block" key={`region-${i}`}>
150
- <button type="button" className="remove-column" onClick={(event) => {
151
- event.preventDefault()
152
- removeColumn(i)
153
- }}>Remove
154
- </button>
155
- <TextField value={label} label="Region Label" fieldName="label" i={i} updateField={updateField}/>
156
- <div className="two-col-inputs">
157
- <TextField value={color} label="Text Color" fieldName="color" updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)}/>
158
- <TextField value={background} label="Background" fieldName="background" updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)}/>
159
- </div>
160
- <div className="two-col-inputs">
161
- <TextField value={from} label="From Value" fieldName="from" updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)}/>
162
- <TextField value={to} label="To Value" fieldName="to" updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)}/>
170
+ {config.regions &&
171
+ config.regions.map(({ label, color, from, to, background }, i) => (
172
+ <div className='edit-block' key={`region-${i}`}>
173
+ <button
174
+ type='button'
175
+ className='remove-column'
176
+ onClick={event => {
177
+ event.preventDefault()
178
+ removeColumn(i)
179
+ }}
180
+ >
181
+ Remove
182
+ </button>
183
+ <TextField value={label} label='Region Label' fieldName='label' i={i} updateField={updateField} />
184
+ <div className='two-col-inputs'>
185
+ <TextField value={color} label='Text Color' fieldName='color' updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)} />
186
+ <TextField value={background} label='Background' fieldName='background' updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)} />
187
+ </div>
188
+ <div className='two-col-inputs'>
189
+ <TextField value={from} label='From Value' fieldName='from' updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)} />
190
+ <TextField value={to} label='To Value' fieldName='to' updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)} />
191
+ </div>
163
192
  </div>
164
- </div>
165
- ))}
193
+ ))}
166
194
  {!config.regions && <p style={{ textAlign: 'center' }}>There are currently no regions.</p>}
167
- <button type="button" className="btn full-width" onClick={(e) => {
168
- e.preventDefault()
169
- addColumn()
170
- }}>Add Region
195
+ <button
196
+ type='button'
197
+ className='btn full-width'
198
+ onClick={e => {
199
+ e.preventDefault()
200
+ addColumn()
201
+ }}
202
+ >
203
+ Add Region
171
204
  </button>
172
205
  </>
173
206
  )
174
207
  })
175
208
 
176
- const headerColors = [ 'theme-blue', 'theme-purple', 'theme-brown', 'theme-teal', 'theme-pink', 'theme-orange', 'theme-slate', 'theme-indigo', 'theme-cyan', 'theme-green', 'theme-amber' ]
209
+ const headerColors = ['theme-blue', 'theme-purple', 'theme-brown', 'theme-teal', 'theme-pink', 'theme-orange', 'theme-slate', 'theme-indigo', 'theme-cyan', 'theme-green', 'theme-amber']
177
210
 
178
211
  const EditorPanel = () => {
179
- const {
180
- config,
181
- updateConfig,
182
- transformedData: data,
183
- loading,
184
- colorPalettes,
185
- unfilteredData,
186
- excludedData,
187
- transformedData,
188
- isDashboard,
189
- setParentConfig,
190
- missingRequiredSections,
191
- setFilteredData
192
- } = useContext(Context)
193
-
194
- const {minValue,maxValue,existPositiveValue} = useReduceData(config,unfilteredData);
195
- const {paletteName,isPaletteReversed,filteredPallets,filteredQualitative,dispatch} = useColorPalette(colorPalettes,config);
196
- useEffect(()=>{
197
- if(paletteName) updateConfig({...config, palette:paletteName})
198
- }, [paletteName])
199
-
200
-
201
-
202
- useEffect(()=>{
203
- dispatch({type:"GET_PALETTE",payload:colorPalettes,paletteName:config.palette})
204
- }, [dispatch, config.palette]);
212
+ const { config, updateConfig, transformedData: data, loading, colorPalettes, unfilteredData, excludedData, isDashboard, setParentConfig, missingRequiredSections } = useContext(Context)
213
+
214
+ const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, unfilteredData)
215
+ const { paletteName, isPaletteReversed, filteredPallets, filteredQualitative, dispatch } = useColorPalette(colorPalettes, config)
216
+ useEffect(() => {
217
+ if (paletteName) updateConfig({ ...config, palette: paletteName })
218
+ }, [paletteName]) // eslint-disable-line
219
+
220
+ useEffect(() => {
221
+ dispatch({ type: 'GET_PALETTE', payload: colorPalettes, paletteName: config.palette })
222
+ }, [dispatch, config.palette]) // eslint-disable-line
223
+
224
+ // when the visualization type changes we
225
+ // have to update the individual series type & axis details
226
+ // dataKey is unchanged here.
227
+ // ie. { dataKey: 'series_name', type: 'Bar', axis: 'Left'}
228
+ useEffect(() => {
229
+ let newSeries = []
230
+ if (config.series) {
231
+ newSeries = config.series.map(series => {
232
+ return {
233
+ ...series,
234
+ type: config.visualizationType === 'Combo' ? 'Bar' : config.visualizationType ? config.visualizationType : 'Bar',
235
+ axis: 'Left'
236
+ }
237
+ })
238
+ }
239
+
240
+ updateConfig({
241
+ ...config,
242
+ series: newSeries
243
+ })
244
+ }, [config.visualizationType]) // eslint-disable-line
245
+
246
+ const { hasRightAxis } = useRightAxis({ config: config, yMax: config.yAxis.size, data: config.data, updateConfig })
205
247
 
206
248
  const filterOptions = [
207
249
  {
@@ -219,7 +261,7 @@ const EditorPanel = () => {
219
261
  ]
220
262
 
221
263
  const getItemStyle = (isDragging, draggableStyle) => ({
222
- ...draggableStyle,
264
+ ...draggableStyle
223
265
  })
224
266
 
225
267
  const sortableItemStyles = {
@@ -235,10 +277,10 @@ const EditorPanel = () => {
235
277
  marginRight: '.3em',
236
278
  marginBottom: '.3em',
237
279
  cursor: 'move',
238
- zIndex: '999',
280
+ zIndex: '999'
239
281
  }
240
282
 
241
- const enforceRestrictions = (updatedConfig) => {
283
+ const enforceRestrictions = updatedConfig => {
242
284
  if (updatedConfig.orientation === 'horizontal') {
243
285
  updatedConfig.labels = false
244
286
  }
@@ -260,11 +302,11 @@ const EditorPanel = () => {
260
302
 
261
303
  const isArray = Array.isArray(config[section])
262
304
 
263
- let sectionValue = isArray ? [ ...config[section], newValue ] : { ...config[section], [fieldName]: newValue }
305
+ let sectionValue = isArray ? [...config[section], newValue] : { ...config[section], [fieldName]: newValue }
264
306
 
265
307
  if (null !== subsection) {
266
308
  if (isArray) {
267
- sectionValue = [ ...config[section] ]
309
+ sectionValue = [...config[section]]
268
310
  sectionValue[subsection] = { ...sectionValue[subsection], [fieldName]: newValue }
269
311
  } else if (typeof newValue === 'string') {
270
312
  sectionValue[subsection] = newValue
@@ -280,22 +322,21 @@ const EditorPanel = () => {
280
322
  updateConfig(updatedConfig)
281
323
  }
282
324
 
283
- const [ displayPanel, setDisplayPanel ] = useState(true)
284
- const [ lollipopColorStyle, setLollipopColorStyle ] = useState('two-tone')
325
+ const [displayPanel, setDisplayPanel] = useState(true)
285
326
 
286
327
  if (loading) {
287
328
  return null
288
329
  }
289
330
 
290
- const setLollipopShape = (shape) => {
331
+ const setLollipopShape = shape => {
291
332
  updateConfig({
292
333
  ...config,
293
334
  lollipopShape: shape
294
335
  })
295
336
  }
296
337
 
297
- const removeFilter = (index) => {
298
- let filters = [ ...config.filters ]
338
+ const removeFilter = index => {
339
+ let filters = [...config.filters]
299
340
 
300
341
  filters.splice(index, 1)
301
342
 
@@ -303,7 +344,7 @@ const EditorPanel = () => {
303
344
  }
304
345
 
305
346
  const updateFilterProp = (name, index, value) => {
306
- let filters = [ ...config.filters ]
347
+ let filters = [...config.filters]
307
348
 
308
349
  filters[index][name] = value
309
350
 
@@ -311,29 +352,28 @@ const EditorPanel = () => {
311
352
  }
312
353
 
313
354
  const addNewFilter = () => {
314
- let filters = config.filters ? [ ...config.filters ] : []
355
+ let filters = config.filters ? [...config.filters] : []
315
356
 
316
- filters.push({ values: [] });
357
+ filters.push({ values: [] })
317
358
 
318
- updateConfig({ ...config, filters });
359
+ updateConfig({ ...config, filters })
319
360
  }
320
361
 
321
- const addNewSeries = (seriesKey) => {
322
- let newSeries = config.series ? [ ...config.series ] : []
323
- newSeries.push({ dataKey: seriesKey, type: 'Bar' });
324
- updateConfig({ ...config, series: newSeries });
362
+ const addNewSeries = seriesKey => {
363
+ let newSeries = config.series ? [...config.series] : []
364
+ newSeries.push({ dataKey: seriesKey, type: 'Bar' })
365
+ updateConfig({ ...config, series: newSeries }) // left axis series keys
325
366
  }
326
367
 
327
- const sortSeries = (e) => {
368
+ const sortSeries = e => {
328
369
  const series = config.series[0].dataKey
329
- const sorted = data.sort((a, b) => a[series] - b[series]);
330
- const newData = e === "asc" ? sorted : sorted.reverse();
331
- updateConfig({ ...config }, newData);
370
+ const sorted = data.sort((a, b) => a[series] - b[series])
371
+ const newData = e === 'asc' ? sorted : sorted.reverse()
372
+ updateConfig({ ...config }, newData)
332
373
  }
333
374
 
334
- const removeSeries = (seriesKey) => {
335
-
336
- let series = [ ...config.series ]
375
+ const removeSeries = seriesKey => {
376
+ let series = [...config.series]
337
377
  let seriesIndex = -1
338
378
 
339
379
  for (let i = 0; i < series.length; i++) {
@@ -363,17 +403,17 @@ const EditorPanel = () => {
363
403
  }
364
404
  }
365
405
 
366
- const addNewExclusion = (exclusionKey) => {
367
- let newExclusion = [ ...config.exclusions.keys ]
406
+ const addNewExclusion = exclusionKey => {
407
+ let newExclusion = [...config.exclusions.keys]
368
408
  newExclusion.push(exclusionKey)
369
409
 
370
410
  let payload = { ...config.exclusions, keys: newExclusion }
371
411
  updateConfig({ ...config, exclusions: payload })
372
412
  }
373
413
 
374
- const removeExclusion = (excludeValue) => {
414
+ const removeExclusion = excludeValue => {
375
415
  let exclusionsIndex = -1
376
- let exclusions = [ ...config.exclusions.keys ]
416
+ let exclusions = [...config.exclusions.keys]
377
417
 
378
418
  for (let i = 0; i < exclusions.length; i++) {
379
419
  if (exclusions[i] === excludeValue) {
@@ -399,14 +439,11 @@ const EditorPanel = () => {
399
439
  const getColumns = (filter = true) => {
400
440
  let columns = {}
401
441
 
402
- unfilteredData.map(row => {
403
- Object.keys(row).forEach(columnName => columns[columnName] = true)
442
+ unfilteredData.forEach(row => {
443
+ Object.keys(row).forEach(columnName => (columns[columnName] = true))
404
444
  })
405
445
 
406
446
  if (filter) {
407
- let confidenceUpper = config.confidenceKeys?.upper && config.confidenceKeys?.upper !== ''
408
- let confidenceLower = config.confidenceKeys?.lower && config.confidenceKeys?.lower !== ''
409
-
410
447
  Object.keys(columns).forEach(key => {
411
448
  if (
412
449
  (config.series && config.series.filter(series => series.dataKey === key).length > 0) ||
@@ -424,32 +461,30 @@ const EditorPanel = () => {
424
461
  return Object.keys(columns)
425
462
  }
426
463
 
427
-
428
- const getDataValueOptions = (data)=>{
429
- if(!data) return [];
430
- const set = new Set();
431
- for (let i=0; i<data.length; i++){
432
- for (const [key, value] of Object.entries(data[i])) {
433
- set.add(key)
434
- }
435
-
464
+ const getDataValueOptions = data => {
465
+ if (!data) return []
466
+ const set = new Set()
467
+ for (let i = 0; i < data.length; i++) {
468
+ for (const [key] of Object.entries(data[i])) {
469
+ set.add(key)
436
470
  }
437
- return Array.from(set)
438
- };
439
-
471
+ }
472
+ return Array.from(set)
473
+ }
474
+
440
475
  const getDataValues = (dataKey, unique = false) => {
441
476
  let values = []
442
- excludedData.map(e => {
477
+ excludedData.forEach(e => {
443
478
  values.push(e[dataKey])
444
479
  })
445
- return unique ? [ ...new Set(values) ] : values
480
+ return unique ? [...new Set(values)] : values
446
481
  }
447
482
 
448
- const showBarStyleOptions = ()=>{
449
- if (config.visualizationType === 'Bar' && config.visualizationSubType !== 'stacked' && (config.orientation==='horizontal' || config.orientation==='vertical') ) {
450
- return ['flat','rounded','lollipop']
483
+ const showBarStyleOptions = () => {
484
+ if (config.visualizationType === 'Bar' && config.visualizationSubType !== 'stacked' && (config.orientation === 'horizontal' || config.orientation === 'vertical')) {
485
+ return ['flat', 'rounded', 'lollipop']
451
486
  } else {
452
- return ['flat','rounded']
487
+ return ['flat', 'rounded']
453
488
  }
454
489
  }
455
490
 
@@ -459,18 +494,17 @@ const EditorPanel = () => {
459
494
 
460
495
  const Error = () => {
461
496
  return (
462
- <section className="waiting">
463
- <section className="waiting-container">
497
+ <section className='waiting'>
498
+ <section className='waiting-container'>
464
499
  <h3>Error With Configuration</h3>
465
500
  <p>{config.runtime.editorErrorMessage}</p>
466
501
  </section>
467
502
  </section>
468
503
  )
469
-
470
504
  }
471
505
 
472
506
  const Confirm = () => {
473
- const confirmDone = (e) => {
507
+ const confirmDone = e => {
474
508
  e.preventDefault()
475
509
 
476
510
  let newConfig = { ...config }
@@ -480,11 +514,13 @@ const EditorPanel = () => {
480
514
  }
481
515
 
482
516
  return (
483
- <section className="waiting">
484
- <section className="waiting-container">
517
+ <section className='waiting'>
518
+ <section className='waiting-container'>
485
519
  <h3>Finish Configuring</h3>
486
520
  <p>Set all required options to the left and confirm below to display a preview of the chart.</p>
487
- <button className="btn" style={{ margin: '1em auto' }} disabled={missingRequiredSections()} onClick={confirmDone}>I'm Done</button>
521
+ <button className='btn' style={{ margin: '1em auto' }} disabled={missingRequiredSections()} onClick={confirmDone}>
522
+ I'm Done
523
+ </button>
488
524
  </section>
489
525
  </section>
490
526
  )
@@ -508,17 +544,17 @@ const EditorPanel = () => {
508
544
  }
509
545
 
510
546
  // eslint-disable-next-line react-hooks/exhaustive-deps
511
- }, [ config ])
512
-
547
+ }, [config])
548
+
513
549
  // Set paired bars to be horizontal, even though that option doesn't display
514
550
  useEffect(() => {
515
- if(config.visualizationType === 'Paired Bar') {
516
- updateConfig({
517
- ...config,
518
- orientation: 'horizontal'
551
+ if (config.visualizationType === 'Paired Bar') {
552
+ updateConfig({
553
+ ...config,
554
+ orientation: 'horizontal'
519
555
  })
520
556
  }
521
- }, []);
557
+ }, []) // eslint-disable-line
522
558
 
523
559
  useEffect(() => {
524
560
  if (config.orientation === 'horizontal') {
@@ -527,50 +563,50 @@ const EditorPanel = () => {
527
563
  lollipopShape: config.lollipopShape
528
564
  })
529
565
  }
530
- }, [ config.isLollipopChart, config.lollipopShape ])
566
+ }, [config.isLollipopChart, config.lollipopShape]) // eslint-disable-line
531
567
 
532
568
  const ExclusionsList = useCallback(() => {
533
- const exclusions = [ ...config.exclusions.keys ]
569
+ const exclusions = [...config.exclusions.keys]
534
570
  return (
535
- <ul className="series-list">
571
+ <ul className='series-list'>
536
572
  {exclusions.map((exclusion, index) => {
537
573
  return (
538
574
  <li key={exclusion}>
539
- <div className="series-list__name" data-title={exclusion}>
540
- <div className="series-list__name--text">
541
- {exclusion}
542
- </div>
575
+ <div className='series-list__name' data-title={exclusion}>
576
+ <div className='series-list__name--text'>{exclusion}</div>
543
577
  </div>
544
- <button className="series-list__remove" onClick={() => removeExclusion(exclusion)}>&#215;</button>
578
+ <button className='series-list__remove' onClick={() => removeExclusion(exclusion)}>
579
+ &#215;
580
+ </button>
545
581
  </li>
546
582
  )
547
583
  })}
548
584
  </ul>
549
585
  )
550
- }, [ config ])
586
+ }, [config]) // eslint-disable-line
551
587
 
552
- const ErrorWithLolliopChart = ({ message }) => {
553
- return (
554
- <section className="waiting">
555
- <section className="waiting-container">
556
- <h3>Error With Configuration</h3>
557
- <p>{message}</p>
558
- </section>
559
- </section>
560
- )
588
+ const checkIsLine = type => {
589
+ return type === ('Line' || 'dashed-sm')
561
590
  }
562
591
 
563
592
  const handleFilterChange = (idx1, idx2, filterIndex, filter) => {
564
593
  let filterOrder = filter.values
565
- let [ movedItem ] = filterOrder.splice(idx1, 1)
594
+ let [movedItem] = filterOrder.splice(idx1, 1)
566
595
  filterOrder.splice(idx2, 0, movedItem)
567
- let filters = [ ...config.filters ]
596
+ let filters = [...config.filters]
568
597
  let filterItem = { ...config.filters[filterIndex] }
569
598
  filterItem.active = filter.values[0]
570
- filterItem.values = filterOrder
599
+ filterItem.orderedValues = filterOrder
571
600
  filterItem.order = 'cust'
572
601
  filters[filterIndex] = filterItem
573
- setFilteredData(filters)
602
+ updateConfig({ ...config, filters })
603
+ }
604
+
605
+ const handleSeriesChange = (idx1, idx2) => {
606
+ let seriesOrder = config.series
607
+ let [movedItem] = seriesOrder.splice(idx1, 1)
608
+ seriesOrder.splice(idx2, 0, movedItem)
609
+ updateConfig({ ...config, series: seriesOrder })
574
610
  }
575
611
 
576
612
  if (config.isLollipopChart && config?.series?.length > 1) {
@@ -581,500 +617,787 @@ const EditorPanel = () => {
581
617
  config.runtime.editorErrorMessage = 'Add a data series'
582
618
  }
583
619
 
584
- const section = config.orientation==='horizontal' ? 'xAxis' : 'yAxis';
585
- const [warningMsg,setWarningMsg] = useState({maxMsg:'',minMsg:''});
620
+ const section = config.orientation === 'horizontal' ? 'xAxis' : 'yAxis'
621
+ const [warningMsg, setWarningMsg] = useState({ maxMsg: '', minMsg: '' })
586
622
 
587
623
  const validateMaxValue = () => {
588
- const enteredValue = config[section].max;
589
- let message = '';
590
-
591
- switch(true){
592
- case (enteredValue && parseFloat(enteredValue) < parseFloat(maxValue) && existPositiveValue):
593
- message = 'Max value must be more than '+ maxValue;
594
- break;
595
- case (enteredValue && parseFloat(enteredValue) < 0 && !existPositiveValue):
596
- message = 'Value must be more than or equal to 0';
597
- break;
598
- default : message = '' ;
599
- }
600
- setWarningMsg(function(prevMsg){return{...prevMsg,maxMsg:message}});
601
- };
602
-
603
-
604
- const validateMinValue = ()=>{
605
- const enteredValue = config[section].min;
606
- let minVal = Number(minValue);
607
- let message = '';
608
-
609
- switch(true){
610
- case ((config.visualizationType === 'Line' || config.visualizationType === 'Spark Line') && (enteredValue && parseFloat(enteredValue) > minVal)):
611
- message = 'Value must be less than ' + minValue;
612
- break;
613
- case ((config.visualizationType === 'Bar' || config.visualizationType === 'Combo' ) && enteredValue && minVal > 0 && parseFloat(enteredValue) > 0):
614
- message = 'Value must be less than or equal to 0';
615
- break;
616
- case ( enteredValue && minVal < 0 && parseFloat(enteredValue) > minVal) :
617
- message = 'Value must be less than ' + minValue;
618
- break;
619
- default : message = ''
620
- };
621
- setWarningMsg(function (prevMsg) { return {...prevMsg, minMsg: message}});
622
- };
623
-
624
- useEffect(()=>{
625
- validateMinValue();
626
- validateMaxValue();
627
- },[minValue,maxValue,config]);
624
+ const enteredValue = config[section].max
625
+ let message = ''
626
+
627
+ switch (true) {
628
+ case enteredValue && parseFloat(enteredValue) < parseFloat(maxValue) && existPositiveValue:
629
+ message = 'Max value must be more than ' + maxValue
630
+ break
631
+ case enteredValue && parseFloat(enteredValue) < 0 && !existPositiveValue:
632
+ message = 'Value must be more than or equal to 0'
633
+ break
634
+ default:
635
+ message = ''
636
+ }
637
+ setWarningMsg(function (prevMsg) {
638
+ return { ...prevMsg, maxMsg: message }
639
+ })
640
+ }
641
+
642
+ const validateMinValue = () => {
643
+ const enteredValue = config[section].min
644
+ let minVal = Number(minValue)
645
+ let message = ''
646
+
647
+ switch (true) {
648
+ case (config.visualizationType === 'Line' || config.visualizationType === 'Spark Line') && enteredValue && parseFloat(enteredValue) > minVal:
649
+ message = 'Value must be less than ' + minValue
650
+ break
651
+ case config.visualizationType === 'Combo' && isAllLine && enteredValue && parseFloat(enteredValue) > minVal:
652
+ message = 'Value must be less than ' + minValue
653
+ break
654
+ case (config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && !isAllLine)) && enteredValue && minVal > 0 && parseFloat(enteredValue) > 0:
655
+ message = 'Value must be less than or equal to 0'
656
+ break
657
+ case enteredValue && minVal < 0 && parseFloat(enteredValue) > minVal:
658
+ message = 'Value must be less than ' + minValue
659
+ break
660
+ default:
661
+ message = ''
662
+ }
663
+ setWarningMsg(function (prevMsg) {
664
+ return { ...prevMsg, minMsg: message }
665
+ })
666
+ }
667
+ useEffect(() => {
668
+ validateMinValue()
669
+ validateMaxValue()
670
+ }, [minValue, maxValue, config]) // eslint-disable-line
628
671
 
629
672
  return (
630
- <ErrorBoundary component="EditorPanel">
631
- {config.newViz && <Confirm/>}
632
- {undefined === config.newViz && config.runtime && config.runtime.editorErrorMessage && <Error/>}
673
+ <ErrorBoundary component='EditorPanel'>
674
+ {config.newViz && <Confirm />}
675
+ {undefined === config.newViz && config.runtime && config.runtime.editorErrorMessage && <Error />}
633
676
  <button className={displayPanel ? `editor-toggle` : `editor-toggle collapsed`} title={displayPanel ? `Collapse Editor` : `Expand Editor`} onClick={onBackClick}></button>
634
677
  <section className={`${displayPanel ? 'editor-panel cove' : 'hidden editor-panel cove'}${isDashboard ? ' dashboard' : ''}`}>
635
- <div aria-level="2" role="heading" className="heading-2">Configure Chart</div>
636
- <section className="form-container">
678
+ <div aria-level='2' role='heading' className='heading-2'>
679
+ Configure Chart
680
+ </div>
681
+ <section className='form-container'>
637
682
  <form>
638
683
  <Accordion allowZeroExpanded={true}>
639
- <AccordionItem> {/* General */}
684
+ <AccordionItem>
685
+ {' '}
686
+ {/* General */}
640
687
  <AccordionItemHeading>
641
- <AccordionItemButton>
642
- General
643
- </AccordionItemButton>
688
+ <AccordionItemButton>General</AccordionItemButton>
644
689
  </AccordionItemHeading>
645
690
  <AccordionItemPanel>
646
- <Select value={config.visualizationType} fieldName="visualizationType" label="Chart Type" updateField={updateField} options={[ 'Pie', 'Line', 'Bar', 'Combo', 'Paired Bar', 'Spark Line' ]}/>
647
- {(config.visualizationType === 'Bar'|| config.visualizationType === 'Combo') && <Select value={config.visualizationSubType || 'Regular'} fieldName="visualizationSubType" label="Chart Subtype" updateField={updateField} options={[ 'regular', 'stacked' ]}/>}
648
- {config.visualizationType === 'Bar' && <Select value={config.orientation || 'vertical'} fieldName="orientation" label="Orientation" updateField={updateField} options={[ 'vertical', 'horizontal' ]}/>}
649
- {config.visualizationType === 'Bar' && <Select value={ config.isLollipopChart? 'lollipop': config.barStyle || 'flat'} fieldName="barStyle" label="bar style" updateField={updateField} options={showBarStyleOptions()}/>}
650
- {(config.visualizationType === 'Bar' && config.barStyle==='rounded' ) && <Select value={config.tipRounding||'top'} fieldName="tipRounding" label="tip rounding" updateField={updateField} options={['top','full']}/>}
651
- {(config.visualizationType === 'Bar' && config.barStyle==='rounded' ) && <Select value={config.roundingStyle||'standard'} fieldName="roundingStyle" label="rounding style" updateField={updateField} options={['standard','shallow','finger']}/>}
652
- {(config.visualizationType === 'Bar' && config.orientation === 'horizontal') &&
653
- <Select value={config.yAxis.labelPlacement || 'Below Bar'} section="yAxis" fieldName="labelPlacement" label="Label Placement" updateField={updateField} options={[ 'Below Bar', 'On Date/Category Axis' ]}/>
654
- }
655
- {config.orientation === 'horizontal' && (config.yAxis.labelPlacement === 'Below Bar' || config.yAxis.labelPlacement === 'On Date/Category Axis' || config.visualizationType === 'Paired Bar' ) ? (
656
- <CheckBox value={config.yAxis.displayNumbersOnBar} section="yAxis" fieldName="displayNumbersOnBar" label={config.isLollipopChart ? 'Display Numbers after Bar' : 'Display Numbers on Bar'} updateField={updateField}/>
657
- ): config.visualizationType !== 'Pie' && (
658
- <CheckBox value={config.labels} fieldName="labels" label="Display label on data" updateField={updateField}/>
691
+ <Select value={config.visualizationType} fieldName='visualizationType' label='Chart Type' updateField={updateField} options={['Pie', 'Line', 'Bar', 'Combo', 'Paired Bar', 'Spark Line']} />
692
+ {(config.visualizationType === 'Bar' || config.visualizationType === 'Combo') && <Select value={config.visualizationSubType || 'Regular'} fieldName='visualizationSubType' label='Chart Subtype' updateField={updateField} options={['regular', 'stacked']} />}
693
+ {config.visualizationType === 'Bar' && <Select value={config.orientation || 'vertical'} fieldName='orientation' label='Orientation' updateField={updateField} options={['vertical', 'horizontal']} />}
694
+ {config.visualizationType === 'Bar' && <Select value={config.isLollipopChart ? 'lollipop' : config.barStyle || 'flat'} fieldName='barStyle' label='bar style' updateField={updateField} options={showBarStyleOptions()} />}
695
+ {config.visualizationType === 'Bar' && config.barStyle === 'rounded' && <Select value={config.tipRounding || 'top'} fieldName='tipRounding' label='tip rounding' updateField={updateField} options={['top', 'full']} />}
696
+ {config.visualizationType === 'Bar' && config.barStyle === 'rounded' && <Select value={config.roundingStyle || 'standard'} fieldName='roundingStyle' label='rounding style' updateField={updateField} options={['standard', 'shallow', 'finger']} />}
697
+ {config.visualizationType === 'Bar' && config.orientation === 'horizontal' && <Select value={config.yAxis.labelPlacement || 'Below Bar'} section='yAxis' fieldName='labelPlacement' label='Label Placement' updateField={updateField} options={['Below Bar', 'On Date/Category Axis']} />}
698
+ {config.orientation === 'horizontal' && (config.yAxis.labelPlacement === 'Below Bar' || config.yAxis.labelPlacement === 'On Date/Category Axis' || config.visualizationType === 'Paired Bar') ? (
699
+ <CheckBox value={config.yAxis.displayNumbersOnBar} section='yAxis' fieldName='displayNumbersOnBar' label={config.isLollipopChart ? 'Display Numbers after Bar' : 'Display Numbers on Bar'} updateField={updateField} />
700
+ ) : (
701
+ config.visualizationType !== 'Pie' && <CheckBox value={config.labels} fieldName='labels' label='Display label on data' updateField={updateField} />
659
702
  )}
660
- {config.visualizationType === 'Pie' && <Select fieldName="pieType" label="Pie Chart Type" updateField={updateField} options={[ 'Regular', 'Donut' ]}/>}
661
- <TextField value={config.title} fieldName="title" label="Title" updateField={updateField} />
662
-
703
+ {config.visualizationType === 'Pie' && <Select fieldName='pieType' label='Pie Chart Type' updateField={updateField} options={['Regular', 'Donut']} />}
704
+
705
+ <TextField value={config.title} fieldName='title' label='Title' updateField={updateField} />
663
706
  <TextField
664
- value={config.superTitle}
665
- updateField={updateField}
666
- fieldName='superTitle'
667
- label='Super Title'
668
- placeholder='Super Title'
669
- tooltip={
670
- <Tooltip style={{textTransform: 'none'}}>
671
- <Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
707
+ value={config.superTitle}
708
+ updateField={updateField}
709
+ fieldName='superTitle'
710
+ label='Super Title'
711
+ placeholder='Super Title'
712
+ tooltip={
713
+ <Tooltip style={{ textTransform: 'none' }}>
714
+ <Tooltip.Target>
715
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
716
+ </Tooltip.Target>
672
717
  <Tooltip.Content>
673
- <p>Super Title</p>
718
+ <p>Super Title</p>
674
719
  </Tooltip.Content>
675
720
  </Tooltip>
676
- }
721
+ }
677
722
  />
678
-
723
+
679
724
  <TextField
680
- type='textarea'
681
- value={config.introText}
682
- updateField={updateField}
683
- fieldName='introText'
684
- label='Intro Text'
685
- tooltip={
686
- <Tooltip style={{textTransform: 'none'}}>
687
- <Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
725
+ type='textarea'
726
+ value={config.introText}
727
+ updateField={updateField}
728
+ fieldName='introText'
729
+ label='Intro Text'
730
+ tooltip={
731
+ <Tooltip style={{ textTransform: 'none' }}>
732
+ <Tooltip.Target>
733
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
734
+ </Tooltip.Target>
688
735
  <Tooltip.Content>
689
- <p>Intro Text</p>
736
+ <p>Intro Text</p>
690
737
  </Tooltip.Content>
691
738
  </Tooltip>
692
- }
693
- />
694
-
695
- <TextField type="textarea" value={config.description} fieldName="description" label="Subtext" updateField={updateField} tooltip={
696
- <Tooltip style={{ textTransform: 'none' }}>
697
- <Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }}/></Tooltip.Target>
698
- <Tooltip.Content>
699
- <p>Enter supporting text to display below the data visualization, if applicable. The following HTML tags are supported: strong, em, sup, and sub.</p>
700
- </Tooltip.Content>
701
- </Tooltip>
702
- } />
703
-
739
+ }
740
+ />
741
+
742
+ <TextField
743
+ type='textarea'
744
+ value={config.description}
745
+ fieldName='description'
746
+ label='Subtext'
747
+ updateField={updateField}
748
+ tooltip={
749
+ <Tooltip style={{ textTransform: 'none' }}>
750
+ <Tooltip.Target>
751
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
752
+ </Tooltip.Target>
753
+ <Tooltip.Content>
754
+ <p>Enter supporting text to display below the data visualization, if applicable. The following HTML tags are supported: strong, em, sup, and sub.</p>
755
+ </Tooltip.Content>
756
+ </Tooltip>
757
+ }
758
+ />
759
+
704
760
  <TextField
705
- type='textarea'
706
- value={config.footnotes}
707
- updateField={updateField}
708
- fieldName='footnotes'
709
- label='Footnotes'
710
- tooltip={
711
- <Tooltip style={{textTransform: 'none'}}>
712
- <Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
761
+ type='textarea'
762
+ value={config.footnotes}
763
+ updateField={updateField}
764
+ fieldName='footnotes'
765
+ label='Footnotes'
766
+ tooltip={
767
+ <Tooltip style={{ textTransform: 'none' }}>
768
+ <Tooltip.Target>
769
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
770
+ </Tooltip.Target>
713
771
  <Tooltip.Content>
714
- <p>Footnotes</p>
772
+ <p>Footnotes</p>
715
773
  </Tooltip.Content>
716
774
  </Tooltip>
717
- }
718
- />
775
+ }
776
+ />
719
777
 
720
- {config.visualizationSubType !== 'horizontal' &&
721
- <TextField type="number" value={config.height} fieldName="height" label="Chart Height" updateField={updateField}/>
722
- }
778
+ {config.orientation === 'vertical' && <TextField type='number' value={config.heights.vertical} section='heights' fieldName='vertical' label='Chart Height' updateField={updateField} />}
723
779
  </AccordionItemPanel>
724
780
  </AccordionItem>
725
781
 
726
-
727
- {config.visualizationType !== 'Pie' &&
782
+ {config.visualizationType !== 'Pie' && (
728
783
  <AccordionItem>
729
784
  <AccordionItemHeading>
730
- <AccordionItemButton>
731
- Data Series {((!config.series || config.series.length === 0) || (config.visualizationType === 'Paired Bar' && config.series.length < 2)) && <WarningImage width="25" className="warning-icon"/>}
732
- </AccordionItemButton>
785
+ <AccordionItemButton>Data Series {(!config.series || config.series.length === 0 || (config.visualizationType === 'Paired Bar' && config.series.length < 2)) && <WarningImage width='25' className='warning-icon' />}</AccordionItemButton>
733
786
  </AccordionItemHeading>
734
787
  <AccordionItemPanel>
735
- {((!config.series || config.series.length === 0) && (config.visualizationType !== 'Paired Bar')) && <p className="warning">At least one series is required</p>}
736
- {((!config.series || config.series.length === 0 || config.series.length < 2) && (config.visualizationType === 'Paired Bar')) && <p className="warning">Select two data series for paired bar chart (e.g., Male and Female).</p>}
788
+ {(!config.series || config.series.length === 0) && config.visualizationType !== 'Paired Bar' && <p className='warning'>At least one series is required</p>}
789
+ {(!config.series || config.series.length === 0 || config.series.length < 2) && config.visualizationType === 'Paired Bar' && <p className='warning'>Select two data series for paired bar chart (e.g., Male and Female).</p>}
737
790
  {config.series && config.series.length !== 0 && (
738
791
  <>
739
792
  <fieldset>
740
- <legend className="edit-label float-left">
741
- Displaying
742
- </legend>
793
+ <legend className='edit-label float-left'>Displaying</legend>
743
794
  <Tooltip style={{ textTransform: 'none' }}>
744
- <Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }}/></Tooltip.Target>
795
+ <Tooltip.Target>
796
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
797
+ </Tooltip.Target>
745
798
  <Tooltip.Content>
746
799
  <p>A data series is a set of related data points plotted in a chart and typically represented in the chart legend.</p>
747
800
  </Tooltip.Content>
748
801
  </Tooltip>
749
802
  </fieldset>
750
- <ul className="series-list">
751
- {config.series.map((series, i) => {
752
803
 
753
- if (config.visualizationType === 'Combo') {
754
- let changeType = (i, value) => {
755
- let series = [ ...config.series ]
756
- series[i].type = value
804
+ <DragDropContext onDragEnd={({ source, destination }) => handleSeriesChange(source.index, destination.index)}>
805
+ <Droppable droppableId='filter_order'>
806
+ {provided => (
807
+ <ul {...provided.droppableProps} className='series-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
808
+ {config.series.map((series, i) => {
809
+ if (config.visualizationType === 'Combo') {
810
+ let changeType = (i, value) => {
811
+ let series = [...config.series]
812
+ series[i].type = value
813
+
814
+ series[i].axis = 'Left'
815
+
816
+ updateConfig({ ...config, series })
817
+ }
818
+
819
+ let typeDropdown = (
820
+ <select
821
+ value={series.type}
822
+ onChange={event => {
823
+ changeType(i, event.target.value)
824
+ }}
825
+ style={{ width: '100px', marginRight: '10px' }}
826
+ >
827
+ <option value='' default>
828
+ Select
829
+ </option>
830
+ <option value='Bar'>Bar</option>
831
+ <option value='Line'>Solid Line</option>
832
+ <option value='dashed-sm'>Small Dashed</option>
833
+ <option value='dashed-md'>Medium Dashed</option>
834
+ <option value='dashed-lg'>Large Dashed</option>
835
+ </select>
836
+ )
837
+
838
+ return (
839
+ <Draggable key={series.dataKey} draggableId={`draggableFilter-${series.dataKey}`} index={i}>
840
+ {(provided, snapshot) => (
841
+ <li>
842
+ <div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
843
+ <div className={`series-list__name${series.dataKey.length > 15 ? ' series-list__name--truncate' : ''}`} data-title={series.dataKey}>
844
+ <div className='series-list__name-text'>{series.dataKey}</div>
845
+ </div>
846
+ <span>
847
+ <span className='series-list__dropdown'>{typeDropdown}</span>
848
+ {config.series && config.series.length > 1 && (
849
+ <button className='series-list__remove' onClick={() => removeSeries(series.dataKey)}>
850
+ &#215;
851
+ </button>
852
+ )}
853
+ </span>
854
+ </div>
855
+ </li>
856
+ )}
857
+ </Draggable>
858
+ )
859
+ }
860
+
861
+ return (
862
+ <Draggable key={series.dataKey} draggableId={`draggableFilter-${series.dataKey}`} index={i}>
863
+ {(provided, snapshot) => (
864
+ <li
865
+ key={series.dataKey}
866
+ className={snapshot.isDragging ? 'currently-dragging' : ''}
867
+ style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)}
868
+ ref={provided.innerRef}
869
+ {...provided.draggableProps}
870
+ {...provided.dragHandleProps}
871
+ >
872
+ {/*<div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>*/}
873
+ <div className='series-list__name' data-title={series.dataKey}>
874
+ <div className='series-list__name--text'>{series.dataKey}</div>
875
+ </div>
876
+ {config.series && config.series.length > 1 && (
877
+ <button className='series-list__remove' onClick={() => removeSeries(series.dataKey)}>
878
+ &#215;
879
+ </button>
880
+ )}
881
+ {/*</div>*/}
882
+ </li>
883
+ )}
884
+ </Draggable>
885
+ )
886
+ })}
887
+ {provided.placeholder}
888
+ </ul>
889
+ )}
890
+ </Droppable>
891
+ </DragDropContext>
892
+ </>
893
+ )}
894
+
895
+ <Select
896
+ fieldName='visualizationType'
897
+ label='Add Data Series'
898
+ initial='Select'
899
+ onChange={e => {
900
+ if (e.target.value !== '' && e.target.value !== 'Select') {
901
+ addNewSeries(e.target.value)
902
+ }
903
+ e.target.value = ''
904
+ }}
905
+ options={getColumns()}
906
+ />
907
+ {config.series && config.series.length <= 1 && config.visualizationType === 'Bar' && (
908
+ <>
909
+ <span className='divider-heading'>Confidence Keys</span>
910
+ <Select value={config.confidenceKeys.upper || ''} section='confidenceKeys' fieldName='upper' label='Upper' updateField={updateField} initial='Select' options={getColumns()} />
911
+ <Select value={config.confidenceKeys.lower || ''} section='confidenceKeys' fieldName='lower' label='Lower' updateField={updateField} initial='Select' options={getColumns()} />
912
+ </>
913
+ )}
914
+
915
+ {config.series && config.series.length === 1 && <Select fieldName='visualizationType' label='Rank by Value' initial='Select' onChange={e => sortSeries(e.target.value)} options={['asc', 'desc']} />}
916
+ </AccordionItemPanel>
917
+ </AccordionItem>
918
+ )}
919
+
920
+ {hasRightAxis && config.series && config.visualizationType === 'Combo' && (
921
+ <AccordionItem>
922
+ <AccordionItemHeading>
923
+ <AccordionItemButton>Assign Data Series Axis</AccordionItemButton>
924
+ </AccordionItemHeading>
925
+ <AccordionItemPanel>
926
+ <p>Only line series data can be assigned to the right axis. Check the data series section above.</p>
927
+ {config.series && config.series.filter(series => checkIsLine(series.type)) && (
928
+ <>
929
+ <fieldset>
930
+ <legend className='edit-label float-left'>Displaying</legend>
931
+ <Tooltip style={{ textTransform: 'none' }}>
932
+ <Tooltip.Target>
933
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
934
+ </Tooltip.Target>
935
+ <Tooltip.Content>
936
+ <p>Assign an axis for the series</p>
937
+ </Tooltip.Content>
938
+ </Tooltip>
939
+ </fieldset>
940
+ <ul className='series-list'>
941
+ {config.series &&
942
+ config.series.map((series, i) => {
943
+ if (series.type === 'Bar') return false // can't set individual bars atm.
944
+
945
+ let changeAxis = (i, value) => {
946
+ let series = [...config.series]
947
+ series[i].axis = value
757
948
  updateConfig({ ...config, series })
758
949
  }
759
950
 
760
- let typeDropdown = (
761
- <select value={series.type} onChange={(event) => {
762
- changeType(i, event.target.value)
763
- }} style={{ width: '100px', marginRight: '10px' }}>
764
- <option value="" default>Select</option>
765
- <option value="Bar">Bar</option>
766
- <option value="Line">Solid Line</option>
767
- <option value="dashed-sm">Small Dashed</option>
768
- <option value="dashed-md">Medium Dashed</option>
769
- <option value="dashed-lg">Large Dashed</option>
951
+ let axisDropdown = (
952
+ <select
953
+ value={series.axis}
954
+ onChange={event => {
955
+ changeAxis(i, event.target.value)
956
+ }}
957
+ style={{ width: '100px', marginRight: '10px' }}
958
+ >
959
+ <option value='Left' default>
960
+ left
961
+ </option>
962
+ <option value='Right'>right</option>
770
963
  </select>
771
964
  )
772
965
 
773
966
  return (
774
967
  <li key={series.dataKey}>
775
968
  <div className={`series-list__name${series.dataKey.length > 15 ? ' series-list__name--truncate' : ''}`} data-title={series.dataKey}>
776
- <div className="series-list__name-text">{series.dataKey}</div>
969
+ <div className='series-list__name-text'>{series.dataKey}</div>
777
970
  </div>
778
971
  <span>
779
- <span className="series-list__dropdown">{typeDropdown}</span>
780
- {config.series && config.series.length > 1 &&
781
- <button className="series-list__remove" onClick={() => removeSeries(series.dataKey)}>&#215;</button>
782
- }
972
+ <span className='series-list__dropdown'>{axisDropdown}</span>
783
973
  </span>
784
974
  </li>
785
975
  )
786
- }
787
-
788
- return (
789
- <li key={series.dataKey}>
790
- <div className="series-list__name" data-title={series.dataKey}>
791
- <div className="series-list__name--text">
792
- {series.dataKey}
793
- </div>
794
- </div>
795
- {config.series && config.series.length > 1 &&
796
- <button className="series-list__remove" onClick={() => removeSeries(series.dataKey)}>&#215;</button>
797
- }
798
- </li>
799
- )
800
- })}
976
+ })}
801
977
  </ul>
802
- </>)}
803
-
804
- <Select fieldName="visualizationType" label="Add Data Series" initial="Select" onChange={(e) => {
805
- if (e.target.value !== '' && e.target.value !== 'Select') {
806
- addNewSeries(e.target.value)
807
- }
808
- e.target.value = ''
809
- }} options={getColumns()}/>
810
- {config.series && config.series.length <= 1 && config.visualizationType === 'Bar' && (
811
- <>
812
- <span className="divider-heading">Confidence Keys</span>
813
- <Select value={config.confidenceKeys.upper || ''} section="confidenceKeys" fieldName="upper" label="Upper" updateField={updateField} initial="Select" options={getColumns()}/>
814
- <Select value={config.confidenceKeys.lower || ''} section="confidenceKeys" fieldName="lower" label="Lower" updateField={updateField} initial="Select" options={getColumns()}/>
815
978
  </>
816
979
  )}
817
-
818
- {config.series && config.series.length === 1 && <Select
819
- fieldName="visualizationType"
820
- label="Rank by Value"
821
- initial="Select"
822
- onChange={(e) => sortSeries(e.target.value)}
823
- options={['asc', 'desc']} />}
824
-
825
980
  </AccordionItemPanel>
826
981
  </AccordionItem>
827
- }
982
+ )}
828
983
 
829
984
  <AccordionItem>
830
985
  <AccordionItemHeading>
831
986
  <AccordionItemButton>
832
- {config.visualizationType !== 'Pie'
833
- ? config.visualizationType === 'Bar' ? 'Value Axis' : 'Value Axis'
834
- : 'Data Format'
835
- }
836
- {config.visualizationType === 'Pie' && !config.yAxis.dataKey && <WarningImage width="25" className="warning-icon"/>}
987
+ {config.visualizationType !== 'Pie' ? (config.orientation !== 'horizontal' ? 'Left Value Axis' : 'Value Axis') : 'Data Format'}
988
+ {config.visualizationType === 'Pie' && !config.yAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
837
989
  </AccordionItemButton>
838
990
  </AccordionItemHeading>
839
991
  <AccordionItemPanel>
840
- {config.visualizationType === 'Pie' &&
841
- <Select value={config.yAxis.dataKey || ''} section="yAxis" fieldName="dataKey" label="Data Column" initial="Select" required={true} updateField={updateField} options={getColumns(false)} tooltip={
842
- <Tooltip style={{ textTransform: 'none' }}>
843
- <Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }}/></Tooltip.Target>
844
- <Tooltip.Content>
845
- <p>Select the source data to be visually represented.</p>
846
- </Tooltip.Content>
847
- </Tooltip>
848
- }/>
849
- }
992
+ {config.visualizationType === 'Pie' && (
993
+ <Select
994
+ value={config.yAxis.dataKey || ''}
995
+ section='yAxis'
996
+ fieldName='dataKey'
997
+ label='Data Column'
998
+ initial='Select'
999
+ required={true}
1000
+ updateField={updateField}
1001
+ options={getColumns(false)}
1002
+ tooltip={
1003
+ <Tooltip style={{ textTransform: 'none' }}>
1004
+ <Tooltip.Target>
1005
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1006
+ </Tooltip.Target>
1007
+ <Tooltip.Content>
1008
+ <p>Select the source data to be visually represented.</p>
1009
+ </Tooltip.Content>
1010
+ </Tooltip>
1011
+ }
1012
+ />
1013
+ )}
850
1014
  {config.visualizationType !== 'Pie' && (
851
1015
  <>
852
- <TextField value={config.yAxis.label} section="yAxis" fieldName="label" label="Label" updateField={updateField}/>
853
- <TextField value={config.yAxis.numTicks} placeholder="Auto" type="number" section="yAxis" fieldName="numTicks" label="Number of ticks" className="number-narrow" updateField={updateField}/>
854
- <TextField value={config.yAxis.size} type="number" section="yAxis" fieldName="size" label={config.orientation === 'horizontal' ? 'Size (Height)' : 'Size (Width)'} className="number-narrow" updateField={updateField} tooltip={
855
- <Tooltip style={{ textTransform: 'none' }}>
856
- <Tooltip.Target><Icon display="question"/></Tooltip.Target>
857
- <Tooltip.Content>
858
- <p>{`Increase the size if elements in the ${config.orientation} axis are being crowded or hidden behind other elements. Decrease if less space is required for the value axis.`}</p>
859
- </Tooltip.Content>
860
- </Tooltip>
861
- }/>
862
- {config.orientation !== 'horizontal' && <CheckBox value={config.yAxis.gridLines} section="yAxis" fieldName="gridLines" label="Display Gridlines" updateField={updateField}/>}
1016
+ <TextField value={config.yAxis.label} section='yAxis' fieldName='label' label='Label' updateField={updateField} />
1017
+ {config.runtime.seriesKeys && config.runtime.seriesKeys.length === 1 && <CheckBox value={config.isLegendValue} fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />}
1018
+ <TextField value={config.yAxis.numTicks} placeholder='Auto' type='number' section='yAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1019
+ <TextField
1020
+ value={config.yAxis.size}
1021
+ type='number'
1022
+ section='yAxis'
1023
+ fieldName='size'
1024
+ label={config.orientation === 'horizontal' ? 'Size (Height)' : 'Size (Width)'}
1025
+ className='number-narrow'
1026
+ updateField={updateField}
1027
+ tooltip={
1028
+ <Tooltip style={{ textTransform: 'none' }}>
1029
+ <Tooltip.Target>
1030
+ <Icon display='question' />
1031
+ </Tooltip.Target>
1032
+ <Tooltip.Content>
1033
+ <p>{`Increase the size if elements in the ${config.orientation} axis are being crowded or hidden behind other elements. Decrease if less space is required for the value axis.`}</p>
1034
+ </Tooltip.Content>
1035
+ </Tooltip>
1036
+ }
1037
+ />
1038
+ {config.orientation === 'horizontal' && <TextField value={config.xAxis.labelOffset} section='xAxis' fieldName='labelOffset' label='Label offset' type='number' className='number-narrow' updateField={updateField} />}
1039
+ {config.orientation !== 'horizontal' && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Display Gridlines' updateField={updateField} />}
863
1040
  </>
864
1041
  )}
865
- <span className="divider-heading">Number Formatting</span>
866
- <CheckBox value={config.dataFormat.commas} section="dataFormat" fieldName="commas" label="Add commas" updateField={updateField}/>
867
- <TextField value={config.dataFormat.roundTo} type="number" section="dataFormat" fieldName="roundTo" label="Round to decimal point" className="number-narrow" updateField={updateField} min={0}/>
868
- <div className="two-col-inputs">
869
- <TextField value={config.dataFormat.prefix} section="dataFormat" fieldName="prefix" label="Prefix" updateField={updateField} tooltip={
870
- <Tooltip style={{ textTransform: 'none' }}>
871
- <Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }}/></Tooltip.Target>
872
- <Tooltip.Content>
873
- {config.visualizationType === 'Pie' && <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>}
874
- {config.visualizationType !== 'Pie' && <p>Enter a data prefix (such as "$"), if applicable.</p>}
875
- </Tooltip.Content>
876
- </Tooltip>
877
- }/>
878
- <TextField value={config.dataFormat.suffix} section="dataFormat" fieldName="suffix" label="Suffix" updateField={updateField} tooltip={
1042
+ <span className='divider-heading'>Number Formatting</span>
1043
+ <CheckBox value={config.dataFormat.commas} section='dataFormat' fieldName='commas' label='Add commas' updateField={updateField} />
1044
+ <CheckBox
1045
+ value={config.dataFormat.abbreviated}
1046
+ section='dataFormat'
1047
+ fieldName='abbreviated'
1048
+ label='Abbreviate Axis Values'
1049
+ updateField={updateField}
1050
+ tooltip={
879
1051
  <Tooltip style={{ textTransform: 'none' }}>
880
- <Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }}/></Tooltip.Target>
1052
+ <Tooltip.Target>
1053
+ <Icon display='question' />
1054
+ </Tooltip.Target>
881
1055
  <Tooltip.Content>
882
- {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
883
- {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1056
+ <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
884
1057
  </Tooltip.Content>
885
1058
  </Tooltip>
886
- }/>
1059
+ }
1060
+ />
1061
+ <TextField value={config.dataFormat.roundTo} type='number' section='dataFormat' fieldName='roundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1062
+ <div className='two-col-inputs'>
1063
+ <TextField
1064
+ value={config.dataFormat.prefix}
1065
+ section='dataFormat'
1066
+ fieldName='prefix'
1067
+ label='Prefix'
1068
+ updateField={updateField}
1069
+ tooltip={
1070
+ <Tooltip style={{ textTransform: 'none' }}>
1071
+ <Tooltip.Target>
1072
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1073
+ </Tooltip.Target>
1074
+ <Tooltip.Content>
1075
+ {config.visualizationType === 'Pie' && <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>}
1076
+ {config.visualizationType !== 'Pie' && <p>Enter a data prefix (such as "$"), if applicable.</p>}
1077
+ </Tooltip.Content>
1078
+ </Tooltip>
1079
+ }
1080
+ />
1081
+ <TextField
1082
+ value={config.dataFormat.suffix}
1083
+ section='dataFormat'
1084
+ fieldName='suffix'
1085
+ label='Suffix'
1086
+ updateField={updateField}
1087
+ tooltip={
1088
+ <Tooltip style={{ textTransform: 'none' }}>
1089
+ <Tooltip.Target>
1090
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1091
+ </Tooltip.Target>
1092
+ <Tooltip.Content>
1093
+ {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1094
+ {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1095
+ </Tooltip.Content>
1096
+ </Tooltip>
1097
+ }
1098
+ />
887
1099
  </div>
888
-
889
- {(config.orientation === 'horizontal') ? // horizontal - x is vertical y is horizontal
890
- <>
891
- <CheckBox value={config.xAxis.hideAxis} section="xAxis" fieldName="hideAxis" label="Hide Axis" updateField={updateField} />
892
- <CheckBox value={config.xAxis.hideLabel} section="xAxis" fieldName="hideLabel" label="Hide Label" updateField={updateField} />
893
- <CheckBox value={config.xAxis.hideTicks} section="xAxis" fieldName="hideTicks" label="Hide Ticks" updateField={updateField} />
894
- <TextField value={config.xAxis.max} section='xAxis' fieldName='max' label='update max value' type='number' placeholder='Auto' updateField={updateField} />
895
- <span style={{color:'red',display:'block'}} >{warningMsg.maxMsg}</span>
896
- </>
897
- : (config.visualizationType !=='Pie') &&
1100
+
1101
+ {config.orientation === 'horizontal' ? ( // horizontal - x is vertical y is horizontal
898
1102
  <>
899
- <CheckBox value={config.yAxis.hideAxis} section="yAxis" fieldName="hideAxis" label="Hide Axis" updateField={updateField} />
900
- <CheckBox value={config.yAxis.hideLabel} section="yAxis" fieldName="hideLabel" label="Hide Label" updateField={updateField} />
901
- <CheckBox value={config.yAxis.hideTicks} section="yAxis" fieldName="hideTicks" label="Hide Ticks" updateField={updateField} />
902
- <TextField value={config.yAxis.max} section='yAxis' fieldName='max' type='number' label='update max value' placeholder='Auto' updateField={updateField} />
903
- <span style={{color:'red',display:'block'}} >{warningMsg.maxMsg}</span>
904
- <TextField value={config.yAxis.min} section='yAxis' fieldName='min' type='number' label='update min value' placeholder='Auto' updateField={updateField} />
905
- <span style={{color:'red',display:'block'}} >{warningMsg.minMsg}</span>
1103
+ <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1104
+ <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1105
+ <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
1106
+ <TextField value={config.xAxis.max} section='xAxis' fieldName='max' label='update max value' type='number' placeholder='Auto' updateField={updateField} />
1107
+ <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
906
1108
  </>
907
- }
1109
+ ) : (
1110
+ config.visualizationType !== 'Pie' && (
1111
+ <>
1112
+ <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1113
+ <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1114
+ <CheckBox value={config.yAxis.hideTicks} section='yAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
1115
+ <TextField value={config.yAxis.max} section='yAxis' fieldName='max' type='number' label='update max value' placeholder='Auto' updateField={updateField} />
1116
+ <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1117
+ <TextField value={config.yAxis.min} section='yAxis' fieldName='min' type='number' label='update min value' placeholder='Auto' updateField={updateField} />
1118
+ <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1119
+ </>
1120
+ )
1121
+ )}
908
1122
  </AccordionItemPanel>
909
1123
  </AccordionItem>
910
1124
 
1125
+ {/* Right Value Axis Settings */}
1126
+ {hasRightAxis && (
1127
+ <AccordionItem>
1128
+ <AccordionItemHeading>
1129
+ <AccordionItemButton>Right Value Axis</AccordionItemButton>
1130
+ </AccordionItemHeading>
1131
+ <AccordionItemPanel>
1132
+ <TextField value={config.yAxis.rightLabel} section='yAxis' fieldName='rightLabel' label='Label' updateField={updateField} />
1133
+ <TextField value={config.yAxis.rightNumTicks} placeholder='Auto' type='number' section='yAxis' fieldName='rightNumTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1134
+ <TextField value={config.yAxis.rightAxisSize} type='number' section='yAxis' fieldName='rightAxisSize' label='Size (Width)' className='number-narrow' updateField={updateField} />
1135
+ <TextField value={config.yAxis.rightLabelOffsetSize} type='number' section='yAxis' fieldName='rightLabelOffsetSize' label='Label Offset' className='number-narrow' updateField={updateField} />
1136
+
1137
+ <span className='divider-heading'>Number Formatting</span>
1138
+ <CheckBox value={config.dataFormat.rightCommas} section='dataFormat' fieldName='rightCommas' label='Add commas' updateField={updateField} />
1139
+ <TextField value={config.dataFormat.rightRoundTo} type='number' section='dataFormat' fieldName='rightRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1140
+ <div className='two-col-inputs'>
1141
+ <TextField
1142
+ value={config.dataFormat.rightPrefix}
1143
+ section='dataFormat'
1144
+ fieldName='rightPrefix'
1145
+ label='Prefix'
1146
+ updateField={updateField}
1147
+ tooltip={
1148
+ <Tooltip style={{ textTransform: 'none' }}>
1149
+ <Tooltip.Target>
1150
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1151
+ </Tooltip.Target>
1152
+ <Tooltip.Content>
1153
+ {config.visualizationType === 'Pie' && <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>}
1154
+ {config.visualizationType !== 'Pie' && <p>Enter a data prefix (such as "$"), if applicable.</p>}
1155
+ </Tooltip.Content>
1156
+ </Tooltip>
1157
+ }
1158
+ />
1159
+ <TextField
1160
+ value={config.dataFormat.rightSuffix}
1161
+ section='dataFormat'
1162
+ fieldName='rightSuffix'
1163
+ label='Suffix'
1164
+ updateField={updateField}
1165
+ tooltip={
1166
+ <Tooltip style={{ textTransform: 'none' }}>
1167
+ <Tooltip.Target>
1168
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1169
+ </Tooltip.Target>
1170
+ <Tooltip.Content>
1171
+ {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1172
+ {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1173
+ </Tooltip.Content>
1174
+ </Tooltip>
1175
+ }
1176
+ />
1177
+ </div>
1178
+
1179
+ <CheckBox value={config.yAxis.rightHideAxis} section='yAxis' fieldName='rightHideAxis' label='Hide Axis' updateField={updateField} />
1180
+ <CheckBox value={config.yAxis.rightHideLabel} section='yAxis' fieldName='rightHideLabel' label='Hide Label' updateField={updateField} />
1181
+ <CheckBox value={config.yAxis.rightHideTicks} section='yAxis' fieldName='rightHideTicks' label='Hide Ticks' updateField={updateField} />
1182
+ </AccordionItemPanel>
1183
+ </AccordionItem>
1184
+ )}
1185
+
911
1186
  <AccordionItem>
912
1187
  <AccordionItemHeading>
913
1188
  <AccordionItemButton>
914
- {config.visualizationType !== 'Pie'
915
- ? config.visualizationType === 'Bar' ? 'Date/Category Axis' : 'Date/Category Axis'
916
- : 'Segments'
917
- }
918
- {!config.xAxis.dataKey && <WarningImage width="25" className="warning-icon"/>}
1189
+ {config.visualizationType !== 'Pie' ? (config.visualizationType === 'Bar' ? 'Date/Category Axis' : 'Date/Category Axis') : 'Segments'}
1190
+ {!config.xAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
919
1191
  </AccordionItemButton>
920
1192
  </AccordionItemHeading>
921
1193
  <AccordionItemPanel>
922
- {config.visualizationType !== 'Pie' && <>
923
- <Select value={config.xAxis.type} section="xAxis" fieldName="type" label="Data Type" updateField={updateField} options={[ 'categorical', 'date' ]}/>
924
- <Select value={config.xAxis.dataKey || ''} section="xAxis" fieldName="dataKey" label="Data Key" initial="Select" required={true} updateField={updateField} options={getColumns(false)} tooltip={
925
- <Tooltip style={{ textTransform: 'none' }}>
926
- <Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }}/></Tooltip.Target>
927
- <Tooltip.Content>
928
- <p>Select the column or row containing the categories or dates for this axis. </p>
929
- </Tooltip.Content>
930
- </Tooltip>
931
- }/>
932
- </>}
1194
+ {config.visualizationType !== 'Pie' && (
1195
+ <>
1196
+ <Select value={config.xAxis.type} section='xAxis' fieldName='type' label='Data Type' updateField={updateField} options={['categorical', 'date']} />
1197
+ <Select
1198
+ value={config.xAxis.dataKey || ''}
1199
+ section='xAxis'
1200
+ fieldName='dataKey'
1201
+ label='Data Key'
1202
+ initial='Select'
1203
+ required={true}
1204
+ updateField={updateField}
1205
+ options={getColumns(false)}
1206
+ tooltip={
1207
+ <Tooltip style={{ textTransform: 'none' }}>
1208
+ <Tooltip.Target>
1209
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1210
+ </Tooltip.Target>
1211
+ <Tooltip.Content>
1212
+ <p>Select the column or row containing the categories or dates for this axis. </p>
1213
+ </Tooltip.Content>
1214
+ </Tooltip>
1215
+ }
1216
+ />
1217
+ </>
1218
+ )}
933
1219
 
934
- {config.visualizationType === 'Pie' &&
935
- <Select value={config.xAxis.dataKey || ''} section="xAxis" fieldName="dataKey" label="Segment Labels" initial="Select" required={true} updateField={updateField} options={getColumns(false)} tooltip={
936
- <Tooltip style={{ textTransform: 'none' }}>
937
- <Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }}/></Tooltip.Target>
938
- <Tooltip.Content>
939
- <p>Select the source row or column that contains the segment labels. Depending on the data structure, it may be listed as "Key."</p>
940
- </Tooltip.Content>
941
- </Tooltip>
942
- }/>
943
- }
1220
+ {config.visualizationType === 'Pie' && (
1221
+ <Select
1222
+ value={config.xAxis.dataKey || ''}
1223
+ section='xAxis'
1224
+ fieldName='dataKey'
1225
+ label='Segment Labels'
1226
+ initial='Select'
1227
+ required={true}
1228
+ updateField={updateField}
1229
+ options={getColumns(false)}
1230
+ tooltip={
1231
+ <Tooltip style={{ textTransform: 'none' }}>
1232
+ <Tooltip.Target>
1233
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1234
+ </Tooltip.Target>
1235
+ <Tooltip.Content>
1236
+ <p>Select the source row or column that contains the segment labels. Depending on the data structure, it may be listed as "Key."</p>
1237
+ </Tooltip.Content>
1238
+ </Tooltip>
1239
+ }
1240
+ />
1241
+ )}
944
1242
 
945
1243
  {config.visualizationType !== 'Pie' && (
946
1244
  <>
947
- <TextField value={config.xAxis.label} section="xAxis" fieldName="label" label="Label" updateField={updateField}/>
1245
+ <TextField value={config.xAxis.label} section='xAxis' fieldName='label' label='Label' updateField={updateField} />
948
1246
 
949
1247
  {config.xAxis.type === 'date' && (
950
1248
  <>
951
- <p style={{ padding: '1.5em 0 0.5em', fontSize: '.9rem', lineHeight: '1rem' }}>Format how charts should parse and display your dates using <a href="https://github.com/d3/d3-time-format#locale_format" target="_blank" rel="noreferrer">these guidelines</a>.</p>
952
- <TextField value={config.xAxis.dateParseFormat} section="xAxis" fieldName="dateParseFormat" placeholder="Ex. %Y-%m-%d" label="Date Parse Format" updateField={updateField}/>
953
- <TextField value={config.xAxis.dateDisplayFormat} section="xAxis" fieldName="dateDisplayFormat" placeholder="Ex. %Y-%m-%d" label="Date Display Format" updateField={updateField}/>
1249
+ <p style={{ padding: '1.5em 0 0.5em', fontSize: '.9rem', lineHeight: '1rem' }}>
1250
+ Format how charts should parse and display your dates using{' '}
1251
+ <a href='https://github.com/d3/d3-time-format#locale_format' target='_blank' rel='noreferrer'>
1252
+ these guidelines
1253
+ </a>
1254
+ .
1255
+ </p>
1256
+ <TextField value={config.xAxis.dateParseFormat} section='xAxis' fieldName='dateParseFormat' placeholder='Ex. %Y-%m-%d' label='Date Parse Format' updateField={updateField} />
1257
+ <TextField value={config.xAxis.dateDisplayFormat} section='xAxis' fieldName='dateDisplayFormat' placeholder='Ex. %Y-%m-%d' label='Date Display Format' updateField={updateField} />
954
1258
  </>
955
1259
  )}
956
1260
 
957
- <CheckBox value={config.exclusions.active} section="exclusions" fieldName="active" label={config.xAxis.type === 'date' ? 'Limit by start and/or end dates' : 'Exclude one or more values'} tooltip={
958
- <Tooltip style={{ textTransform: 'none' }}>
959
- <Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }}/></Tooltip.Target>
960
- <Tooltip.Content>
961
- <p>When this option is checked, you can select source-file values for exclusion from the date/category axis. </p>
962
- </Tooltip.Content>
963
- </Tooltip>
964
- } updateField={updateField}/>
1261
+ <CheckBox
1262
+ value={config.exclusions.active}
1263
+ section='exclusions'
1264
+ fieldName='active'
1265
+ label={config.xAxis.type === 'date' ? 'Limit by start and/or end dates' : 'Exclude one or more values'}
1266
+ tooltip={
1267
+ <Tooltip style={{ textTransform: 'none' }}>
1268
+ <Tooltip.Target>
1269
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1270
+ </Tooltip.Target>
1271
+ <Tooltip.Content>
1272
+ <p>When this option is checked, you can select source-file values for exclusion from the date/category axis. </p>
1273
+ </Tooltip.Content>
1274
+ </Tooltip>
1275
+ }
1276
+ updateField={updateField}
1277
+ />
965
1278
 
966
- {config.exclusions.active &&
1279
+ {config.exclusions.active && (
967
1280
  <>
968
- {config.xAxis.type === 'categorical' &&
1281
+ {config.xAxis.type === 'categorical' && (
969
1282
  <>
970
- {config.exclusions.keys.length > 0 &&
1283
+ {config.exclusions.keys.length > 0 && (
971
1284
  <>
972
1285
  <fieldset>
973
- <legend className="edit-label">Excluded Keys</legend>
1286
+ <legend className='edit-label'>Excluded Keys</legend>
974
1287
  </fieldset>
975
- <ExclusionsList/>
1288
+ <ExclusionsList />
976
1289
  </>
977
- }
978
-
979
- <Select fieldName="visualizationType" label="Add Exclusion" initial="Select" onChange={(e) => {
980
- if (e.target.value !== '' && e.target.value !== 'Select') {
981
- addNewExclusion(e.target.value)
982
- }
983
- e.target.value = ''
984
- }} options={getDataValues(config.xAxis.dataKey, true)}/>
1290
+ )}
1291
+
1292
+ <Select
1293
+ fieldName='visualizationType'
1294
+ label='Add Exclusion'
1295
+ initial='Select'
1296
+ onChange={e => {
1297
+ if (e.target.value !== '' && e.target.value !== 'Select') {
1298
+ addNewExclusion(e.target.value)
1299
+ }
1300
+ e.target.value = ''
1301
+ }}
1302
+ options={getDataValues(config.xAxis.dataKey, true)}
1303
+ />
985
1304
  </>
986
- }
1305
+ )}
987
1306
 
988
- {config.xAxis.type === 'date' &&
1307
+ {config.xAxis.type === 'date' && (
989
1308
  <>
990
- <TextField type="date" section="exclusions" fieldName="dateStart" label="Start Date" updateField={updateField} value={config.exclusions.dateStart || ''}/>
991
- <TextField type="date" section="exclusions" fieldName="dateEnd" label="End Date" updateField={updateField} value={config.exclusions.dateEnd || ''}/>
1309
+ <TextField type='date' section='exclusions' fieldName='dateStart' label='Start Date' updateField={updateField} value={config.exclusions.dateStart || ''} />
1310
+ <TextField type='date' section='exclusions' fieldName='dateEnd' label='End Date' updateField={updateField} value={config.exclusions.dateEnd || ''} />
992
1311
  </>
993
- }
994
- </>
995
- }
996
-
997
- {config.xAxis.type === 'date' &&
998
- <>
999
- <TextField value={config.xAxis.numTicks} placeholder="Auto" type="number" min="1" section="xAxis" fieldName="numTicks" label="Number of ticks" className="number-narrow" updateField={updateField}/>
1312
+ )}
1000
1313
  </>
1001
- }
1314
+ )}
1315
+ <TextField value={config.xAxis.numTicks} placeholder='Auto' type='number' min='1' section='xAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1002
1316
 
1003
- <TextField value={config.xAxis.size} type="number" min="0" section="xAxis" fieldName="size" label={config.orientation === 'horizontal' ? 'Size (Width)' : 'Size (Height)'} className="number-narrow" updateField={updateField}/>
1317
+ <TextField value={config.xAxis.size} type='number' min='0' section='xAxis' fieldName='size' label={config.orientation === 'horizontal' ? 'Size (Width)' : 'Size (Height)'} className='number-narrow' updateField={updateField} />
1004
1318
 
1005
- {config.yAxis.labelPlacement !== 'Below Bar' &&
1006
- <TextField value={config.xAxis.tickRotation} type="number" min="0" section="xAxis" fieldName="tickRotation" label="Tick rotation (Degrees)" className="number-narrow" updateField={updateField}/>
1007
- }
1008
- {(config.orientation === 'horizontal') ?
1319
+ {config.yAxis.labelPlacement !== 'Below Bar' && <TextField value={config.xAxis.tickRotation} type='number' min='0' section='xAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
1320
+ {config.orientation === 'horizontal' ? (
1009
1321
  <>
1010
- <CheckBox value={config.yAxis.hideAxis} section="yAxis" fieldName="hideAxis" label="Hide Axis" updateField={updateField}/>
1011
- <CheckBox value={config.yAxis.hideLabel} section="yAxis" fieldName="hideLabel" label="Hide Label" updateField={updateField}/>
1322
+ <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1323
+ <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1012
1324
  </>
1013
- :
1325
+ ) : (
1014
1326
  <>
1015
- <CheckBox value={config.xAxis.hideAxis} section="xAxis" fieldName="hideAxis" label="Hide Axis" updateField={updateField}/>
1016
- <CheckBox value={config.xAxis.hideLabel} section="xAxis" fieldName="hideLabel" label="Hide Label" updateField={updateField}/>
1017
- <CheckBox value={config.xAxis.hideTicks} section="xAxis" fieldName="hideTicks" label="Hide Ticks" updateField={updateField}/>
1327
+ <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1328
+ <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1329
+ <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
1018
1330
  </>
1019
- }
1331
+ )}
1020
1332
  </>
1021
1333
  )}
1022
1334
 
1023
- {config.visualizationType === 'Pie' &&
1335
+ {config.visualizationType === 'Pie' && (
1024
1336
  <>
1025
- <CheckBox value={config.exclusions.active} section="exclusions" fieldName="active" label={'Exclude one or more values'} updateField={updateField} tooltip={
1026
- <Tooltip style={{ textTransform: 'none' }}>
1027
- <Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }}/></Tooltip.Target>
1028
- <Tooltip.Content>
1029
- <p>When this option is checked, you can select values for exclusion from the pie segments.</p>
1030
- </Tooltip.Content>
1031
- </Tooltip>
1032
- }/>
1033
- {config.exclusions.active &&
1337
+ <CheckBox
1338
+ value={config.exclusions.active}
1339
+ section='exclusions'
1340
+ fieldName='active'
1341
+ label={'Exclude one or more values'}
1342
+ updateField={updateField}
1343
+ tooltip={
1344
+ <Tooltip style={{ textTransform: 'none' }}>
1345
+ <Tooltip.Target>
1346
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1347
+ </Tooltip.Target>
1348
+ <Tooltip.Content>
1349
+ <p>When this option is checked, you can select values for exclusion from the pie segments.</p>
1350
+ </Tooltip.Content>
1351
+ </Tooltip>
1352
+ }
1353
+ />
1354
+ {config.exclusions.active && (
1034
1355
  <>
1035
- {config.exclusions.keys.length > 0 &&
1356
+ {config.exclusions.keys.length > 0 && (
1036
1357
  <>
1037
1358
  <fieldset>
1038
- <legend className="edit-label">Excluded Keys</legend>
1359
+ <legend className='edit-label'>Excluded Keys</legend>
1039
1360
  </fieldset>
1040
- <ExclusionsList/>
1361
+ <ExclusionsList />
1041
1362
  </>
1042
- }
1043
-
1044
- <Select fieldName="visualizationType" label="Add Exclusion" initial="Select" onChange={(e) => {
1045
- if (e.target.value !== '' && e.target.value !== 'Select') {
1046
- addNewExclusion(e.target.value)
1047
- }
1048
- e.target.value = ''
1049
- }} options={getDataValues(config.xAxis.dataKey, true)}/>
1363
+ )}
1364
+
1365
+ <Select
1366
+ fieldName='visualizationType'
1367
+ label='Add Exclusion'
1368
+ initial='Select'
1369
+ onChange={e => {
1370
+ if (e.target.value !== '' && e.target.value !== 'Select') {
1371
+ addNewExclusion(e.target.value)
1372
+ }
1373
+ e.target.value = ''
1374
+ }}
1375
+ options={getDataValues(config.xAxis.dataKey, true)}
1376
+ />
1050
1377
  </>
1051
- }
1378
+ )}
1052
1379
  </>
1053
- }
1380
+ )}
1054
1381
  </AccordionItemPanel>
1055
1382
  </AccordionItem>
1056
1383
 
1057
- {(config.visualizationType !== 'Pie' && config.visualizationType !== 'Paired Bar') &&
1384
+ {config.visualizationType !== 'Pie' && config.visualizationType !== 'Paired Bar' && (
1058
1385
  <AccordionItem>
1059
1386
  <AccordionItemHeading>
1060
- <AccordionItemButton>
1061
- Regions
1062
- </AccordionItemButton>
1387
+ <AccordionItemButton>Regions</AccordionItemButton>
1063
1388
  </AccordionItemHeading>
1064
1389
  <AccordionItemPanel>
1065
- <Regions config={config} updateConfig={updateConfig}/>
1390
+ <Regions config={config} updateConfig={updateConfig} />
1066
1391
  </AccordionItemPanel>
1067
1392
  </AccordionItem>
1068
- }
1393
+ )}
1069
1394
 
1070
1395
  <AccordionItem>
1071
1396
  <AccordionItemHeading>
1072
- <AccordionItemButton>
1073
- Legend
1074
- </AccordionItemButton>
1397
+ <AccordionItemButton>Legend</AccordionItemButton>
1075
1398
  </AccordionItemHeading>
1076
1399
  <AccordionItemPanel>
1077
- <CheckBox value={config.legend.reverseLabelOrder} section="legend" fieldName="reverseLabelOrder" label="Reverse Labels" updateField={updateField}/>
1400
+ <CheckBox value={config.legend.reverseLabelOrder} section='legend' fieldName='reverseLabelOrder' label='Reverse Labels' updateField={updateField} />
1078
1401
  {/* <fieldset className="checkbox-group">
1079
1402
  <CheckBox value={config.legend.dynamicLegend} section="legend" fieldName="dynamicLegend" label="Dynamic Legend" updateField={updateField}/>
1080
1403
  {config.legend.dynamicLegend && (
@@ -1086,88 +1409,104 @@ useEffect(()=>{
1086
1409
  </>
1087
1410
  )}
1088
1411
  </fieldset> */}
1089
- <CheckBox value={config.legend.hide} section="legend" fieldName="hide" label="Hide Legend" updateField={updateField} tooltip={
1090
- <Tooltip style={{ textTransform: 'none' }}>
1091
- <Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }}/></Tooltip.Target>
1092
- <Tooltip.Content>
1093
- <p>With a single-series chart, consider hiding the legend to reduce visual clutter.</p>
1094
- </Tooltip.Content>
1095
- </Tooltip>
1096
- }/>
1097
-
1098
- {(config.visualizationType==='Bar' && config.visualizationSubType ==="regular" && config.runtime.seriesKeys.length===1 )&& (
1099
- <Select value={config.legend.colorCode} section="legend" fieldName="colorCode" label="Color code by category" initial="Select" updateField={updateField} options={getDataValueOptions(data)}/>
1412
+ <CheckBox
1413
+ value={config.legend.hide}
1414
+ section='legend'
1415
+ fieldName='hide'
1416
+ label='Hide Legend'
1417
+ updateField={updateField}
1418
+ tooltip={
1419
+ <Tooltip style={{ textTransform: 'none' }}>
1420
+ <Tooltip.Target>
1421
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1422
+ </Tooltip.Target>
1423
+ <Tooltip.Content>
1424
+ <p>With a single-series chart, consider hiding the legend to reduce visual clutter.</p>
1425
+ </Tooltip.Content>
1426
+ </Tooltip>
1427
+ }
1428
+ />
1429
+ <CheckBox value={config.legend.showLegendValuesTooltip} section='legend' fieldName='showLegendValuesTooltip' label='Show Legend Values in Tooltip' updateField={updateField} />
1430
+
1431
+ {config.visualizationType === 'Bar' && config.visualizationSubType === 'regular' && config.runtime.seriesKeys.length === 1 && (
1432
+ <Select value={config.legend.colorCode} section='legend' fieldName='colorCode' label='Color code by category' initial='Select' updateField={updateField} options={getDataValueOptions(data)} />
1100
1433
  )}
1101
- <Select value={config.legend.behavior} section="legend" fieldName="behavior" label="Legend Behavior (When clicked)" updateField={updateField} options={[ 'highlight', 'isolate' ]}/>
1102
- <TextField value={config.legend.label} section="legend" fieldName="label" label="Title" updateField={updateField}/>
1103
- <Select value={config.legend.position} section="legend" fieldName="position" label="Position" updateField={updateField} options={[ 'right', 'left' ]}/>
1104
- <TextField type='textarea' value={config.legend.description} updateField={updateField} section='legend' fieldName='description' label='Legend Description' />
1434
+ <Select value={config.legend.behavior} section='legend' fieldName='behavior' label='Legend Behavior (When clicked)' updateField={updateField} options={['highlight', 'isolate']} />
1435
+ <TextField value={config.legend.label} section='legend' fieldName='label' label='Title' updateField={updateField} />
1436
+ <Select value={config.legend.position} section='legend' fieldName='position' label='Position' updateField={updateField} options={['right', 'left', 'bottom']} />
1437
+ {config.legend.position === 'bottom' && <CheckBox value={config.legend.singleRow} section='legend' fieldName='singleRow' label='Single Row Legend' updateField={updateField} />}
1438
+ <TextField type='textarea' value={config.legend.description} updateField={updateField} section='legend' fieldName='description' label='Legend Description' />
1105
1439
  </AccordionItemPanel>
1106
1440
  </AccordionItem>
1107
1441
 
1108
1442
  <AccordionItem>
1109
1443
  <AccordionItemHeading>
1110
- <AccordionItemButton>
1111
- Filters
1112
- </AccordionItemButton>
1444
+ <AccordionItemButton>Filters</AccordionItemButton>
1113
1445
  </AccordionItemHeading>
1114
1446
  <AccordionItemPanel>
1115
- {config.filters && <ul className="filters-list">
1116
- {config.filters.map((filter, index) => (
1117
- <fieldset className="edit-block" key={index}>
1118
- <button type="button" className="remove-column" onClick={() => {
1119
- removeFilter(index)
1120
- }}>Remove
1447
+ {config.filters && (
1448
+ <ul className='filters-list'>
1449
+ {config.filters.map((filter, index) => (
1450
+ <fieldset className='edit-block' key={index}>
1451
+ <button
1452
+ type='button'
1453
+ className='remove-column'
1454
+ onClick={() => {
1455
+ removeFilter(index)
1456
+ }}
1457
+ >
1458
+ Remove
1121
1459
  </button>
1122
1460
  <label>
1123
- <span className="edit-label column-heading">Filter</span>
1124
- <select value={filter.columnName} onChange={(e) => {
1125
- updateFilterProp('columnName', index, e.target.value)
1126
- }}>
1127
- <option value="">- Select Option -</option>
1461
+ <span className='edit-label column-heading'>Filter</span>
1462
+ <select
1463
+ value={filter.columnName}
1464
+ onChange={e => {
1465
+ updateFilterProp('columnName', index, e.target.value)
1466
+ }}
1467
+ >
1468
+ <option value=''>- Select Option -</option>
1128
1469
  {getColumns().map((dataKey, index) => (
1129
- <option value={dataKey} key={index}>{dataKey}</option>
1470
+ <option value={dataKey} key={index}>
1471
+ {dataKey}
1472
+ </option>
1130
1473
  ))}
1131
1474
  </select>
1132
1475
  </label>
1133
1476
  <label>
1134
- <span className="edit-label column-heading">Label</span>
1135
- <input type="text" value={filter.label} onChange={(e) => {
1136
- updateFilterProp('label', index, e.target.value)
1137
- }}/>
1477
+ <span className='edit-label column-heading'>Label</span>
1478
+ <input
1479
+ type='text'
1480
+ value={filter.label}
1481
+ onChange={e => {
1482
+ updateFilterProp('label', index, e.target.value)
1483
+ }}
1484
+ />
1138
1485
  </label>
1139
1486
 
1140
1487
  <label>
1141
- <span className="edit-filterOrder column-heading">Filter Order</span>
1142
- <select value={filter.order ? filter.order : 'asc'} onChange={(e) => updateFilterProp('order', index, e.target.value)}>
1488
+ <span className='edit-filterOrder column-heading'>Filter Order</span>
1489
+ <select value={filter.order ? filter.order : 'asc'} onChange={e => updateFilterProp('order', index, e.target.value)}>
1143
1490
  {filterOptions.map((option, index) => {
1144
- return <option value={option.value} key={`filter-${index}`}>{option.label}</option>
1491
+ return (
1492
+ <option value={option.value} key={`filter-${index}`}>
1493
+ {option.label}
1494
+ </option>
1495
+ )
1145
1496
  })}
1146
1497
  </select>
1147
1498
 
1148
- {filter.order === 'cust' &&
1149
- <DragDropContext
1150
- onDragEnd={({ source, destination }) =>
1151
- handleFilterChange(source.index, destination.index, index, config.filters[index])
1152
- }>
1153
- <Droppable droppableId="filter_order">
1154
- {(provided) => (
1155
- <ul
1156
- {...provided.droppableProps}
1157
- className="sort-list"
1158
- ref={provided.innerRef}
1159
- style={{ marginTop: '1em' }}
1160
- >
1499
+ {filter.order === 'cust' && (
1500
+ <DragDropContext onDragEnd={({ source, destination }) => handleFilterChange(source.index, destination.index, index, config.filters[index])}>
1501
+ <Droppable droppableId='filter_order'>
1502
+ {provided => (
1503
+ <ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
1161
1504
  {config.filters[index]?.values.map((value, index) => {
1162
1505
  return (
1163
1506
  <Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
1164
1507
  {(provided, snapshot) => (
1165
1508
  <li>
1166
- <div className={snapshot.isDragging ? 'currently-dragging' : ''}
1167
- style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)}
1168
- ref={provided.innerRef}
1169
- {...provided.draggableProps}
1170
- {...provided.dragHandleProps}>
1509
+ <div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
1171
1510
  {value}
1172
1511
  </div>
1173
1512
  </li>
@@ -1180,98 +1519,86 @@ useEffect(()=>{
1180
1519
  )}
1181
1520
  </Droppable>
1182
1521
  </DragDropContext>
1183
- }
1522
+ )}
1184
1523
  </label>
1185
-
1186
1524
  </fieldset>
1187
- )
1188
- )}
1189
- </ul>}
1525
+ ))}
1526
+ </ul>
1527
+ )}
1190
1528
  {!config.filters && <p style={{ textAlign: 'center' }}>There are currently no filters.</p>}
1191
- <button type="button" onClick={addNewFilter} className="btn full-width">Add Filter</button>
1529
+ <button type='button' onClick={addNewFilter} className='btn full-width'>
1530
+ Add Filter
1531
+ </button>
1192
1532
  </AccordionItemPanel>
1193
1533
  </AccordionItem>
1194
1534
 
1195
1535
  <AccordionItem>
1196
1536
  <AccordionItemHeading>
1197
- <AccordionItemButton>
1198
- Visual
1199
- </AccordionItemButton>
1537
+ <AccordionItemButton>Visual</AccordionItemButton>
1200
1538
  </AccordionItemHeading>
1201
1539
  <AccordionItemPanel>
1202
-
1203
- {config.isLollipopChart &&
1540
+ {config.isLollipopChart && (
1204
1541
  <>
1205
- <fieldset className="header">
1206
- <legend className="edit-label">Lollipop Shape</legend>
1207
- <div onChange={(e) => {
1208
- setLollipopShape(e.target.value)
1209
- }}>
1210
- <label className="radio-label">
1211
- <input
1212
- type="radio"
1213
- name="lollipopShape"
1214
- value="circle"
1215
- checked={config.lollipopShape === 'circle'}
1216
- />
1542
+ <fieldset className='header'>
1543
+ <legend className='edit-label'>Lollipop Shape</legend>
1544
+ <div
1545
+ onChange={e => {
1546
+ setLollipopShape(e.target.value)
1547
+ }}
1548
+ >
1549
+ <label className='radio-label'>
1550
+ <input type='radio' name='lollipopShape' value='circle' checked={config.lollipopShape === 'circle'} />
1217
1551
  Circle
1218
1552
  </label>
1219
- <label className="radio-label">
1220
- <input
1221
- type="radio"
1222
- name="lollipopShape"
1223
- value="square"
1224
- checked={config.lollipopShape === 'square'}
1225
- />
1553
+ <label className='radio-label'>
1554
+ <input type='radio' name='lollipopShape' value='square' checked={config.lollipopShape === 'square'} />
1226
1555
  Square
1227
1556
  </label>
1228
1557
  </div>
1229
-
1230
1558
  </fieldset>
1231
- <Select value={config.lollipopColorStyle ? config.lollipopColorStyle : 'two-tone'} fieldName="lollipopColorStyle" label="Lollipop Color Style" updateField={updateField} options={[ 'regular', 'two-tone' ]}/>
1232
- <Select value={config.lollipopSize ? config.lollipopSize : 'small'} fieldName="lollipopSize" label="Lollipop Size" updateField={updateField} options={[ 'small', 'medium', 'large' ]}/>
1559
+ <Select value={config.lollipopColorStyle ? config.lollipopColorStyle : 'two-tone'} fieldName='lollipopColorStyle' label='Lollipop Color Style' updateField={updateField} options={['regular', 'two-tone']} />
1560
+ <Select value={config.lollipopSize ? config.lollipopSize : 'small'} fieldName='lollipopSize' label='Lollipop Size' updateField={updateField} options={['small', 'medium', 'large']} />
1233
1561
  </>
1234
- }
1562
+ )}
1235
1563
 
1236
- <Select value={config.fontSize} fieldName="fontSize" label="Font Size" updateField={updateField} options={[ 'small', 'medium', 'large' ]}/>
1564
+ <Select value={config.fontSize} fieldName='fontSize' label='Font Size' updateField={updateField} options={['small', 'medium', 'large']} />
1237
1565
 
1238
- {config.series?.some(series => series.type === 'Bar' || series.type === 'Paired Bar') &&
1239
- <Select value={config.barHasBorder} fieldName="barHasBorder" label="Bar Borders" updateField={updateField} options={[ 'true', 'false' ]}/>
1240
- }
1566
+ {config.series?.some(series => series.type === 'Bar' || series.type === 'Paired Bar') && <Select value={config.barHasBorder} fieldName='barHasBorder' label='Bar Borders' updateField={updateField} options={['true', 'false']} />}
1241
1567
 
1242
- {/* <CheckBox value={config.animate} fieldName="animate" label="Animate Visualization" updateField={updateField} /> */}
1568
+ <CheckBox value={config.animate} fieldName='animate' label='Animate Visualization' updateField={updateField} />
1243
1569
 
1244
1570
  {/*<CheckBox value={config.animateReplay} fieldName="animateReplay" label="Replay Animation When Filters Are Changed" updateField={updateField} />*/}
1245
1571
 
1246
- {((config.series?.some(series => series.type === 'Line') && config.visualizationType === 'Combo') || config.visualizationType === 'Line' || config.visualizationType === "Spark Line") &&
1247
- <Select value={config.lineDatapointStyle} fieldName="lineDatapointStyle" label="Line Datapoint Style" updateField={updateField} options={[ 'hidden', 'hover', 'always show' ]}/>
1248
- }
1572
+ {((config.series?.some(series => series.type === 'Line') && config.visualizationType === 'Combo') || config.visualizationType === 'Line' || config.visualizationType === 'Spark Line') && (
1573
+ <Select value={config.lineDatapointStyle} fieldName='lineDatapointStyle' label='Line Datapoint Style' updateField={updateField} options={['hidden', 'hover', 'always show']} />
1574
+ )}
1249
1575
 
1250
- <label className="header">
1251
- <span className="edit-label">Header Theme</span>
1252
- <ul className="color-palette">
1253
- {headerColors.map((palette) => (
1254
- <button
1576
+ {/* eslint-disable */}
1577
+ <label className='header'>
1578
+ <span className='edit-label'>Header Theme</span>
1579
+ <ul className='color-palette'>
1580
+ {headerColors.map(palette => (
1581
+ <button
1255
1582
  title={palette}
1256
- key={palette}
1257
- onClick={(e) => {
1258
- e.preventDefault();
1583
+ key={palette}
1584
+ onClick={e => {
1585
+ e.preventDefault()
1259
1586
  updateConfig({ ...config, theme: palette })
1260
- }}
1261
- className={config.theme === palette ? 'selected ' + palette : palette}>
1262
- </button>
1587
+ }}
1588
+ className={config.theme === palette ? 'selected ' + palette : palette}
1589
+ ></button>
1263
1590
  ))}
1264
1591
  </ul>
1265
1592
  </label>
1266
1593
  <label>
1267
- <span className="edit-label">Chart Color Palette</span>
1594
+ <span className='edit-label'>Chart Color Palette</span>
1268
1595
  </label>
1596
+ {/* eslint-enable */}
1269
1597
  {/* <InputCheckbox fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={isPaletteReversed} /> */}
1270
- <InputToggle fieldName="isPaletteReversed" size="small" label="Use selected palette in reverse order" updateField={updateField} value={isPaletteReversed}/>
1598
+ <InputToggle fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={isPaletteReversed} />
1271
1599
  <span>Sequential</span>
1272
- <ul className="color-palette">
1273
- {filteredPallets.map((palette) => {
1274
-
1600
+ <ul className='color-palette'>
1601
+ {filteredPallets.map(palette => {
1275
1602
  const colorOne = {
1276
1603
  backgroundColor: colorPalettes[palette][2]
1277
1604
  }
@@ -1285,11 +1612,11 @@ useEffect(()=>{
1285
1612
  }
1286
1613
 
1287
1614
  return (
1288
- <button
1289
- title={palette}
1290
- key={palette}
1291
- onClick={(e) => {
1292
- e.preventDefault();
1615
+ <button
1616
+ title={palette}
1617
+ key={palette}
1618
+ onClick={e => {
1619
+ e.preventDefault()
1293
1620
  updateConfig({ ...config, palette })
1294
1621
  }}
1295
1622
  className={config.palette === palette ? 'selected' : ''}
@@ -1302,9 +1629,8 @@ useEffect(()=>{
1302
1629
  })}
1303
1630
  </ul>
1304
1631
  <span>Non-Sequential</span>
1305
- <ul className="color-palette">
1306
- {filteredQualitative.map((palette) => {
1307
-
1632
+ <ul className='color-palette'>
1633
+ {filteredQualitative.map(palette => {
1308
1634
  const colorOne = {
1309
1635
  backgroundColor: colorPalettes[palette][2]
1310
1636
  }
@@ -1317,13 +1643,12 @@ useEffect(()=>{
1317
1643
  backgroundColor: colorPalettes[palette][6]
1318
1644
  }
1319
1645
 
1320
-
1321
1646
  return (
1322
- <button
1323
- title={palette}
1324
- key={palette}
1325
- onClick={(e) => {
1326
- e.preventDefault();
1647
+ <button
1648
+ title={palette}
1649
+ key={palette}
1650
+ onClick={e => {
1651
+ e.preventDefault()
1327
1652
  updateConfig({ ...config, palette })
1328
1653
  }}
1329
1654
  className={config.palette === palette ? 'selected' : ''}
@@ -1338,82 +1663,103 @@ useEffect(()=>{
1338
1663
 
1339
1664
  {config.visualizationType !== 'Pie' && (
1340
1665
  <>
1341
- <TextField value={config.dataCutoff} type="number" fieldName="dataCutoff" className="number-narrow" label="Data Cutoff" updateField={updateField} tooltip={
1342
- <Tooltip style={{ textTransform: 'none' }}>
1343
- <Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }}/></Tooltip.Target>
1344
- <Tooltip.Content>
1345
- <p>Any value below the cut-off value is included in a special "less than" category. This option supports special conditions like suppressed data.</p>
1346
- </Tooltip.Content>
1347
- </Tooltip>
1348
- }/>
1666
+ <TextField
1667
+ value={config.dataCutoff}
1668
+ type='number'
1669
+ fieldName='dataCutoff'
1670
+ className='number-narrow'
1671
+ label='Data Cutoff'
1672
+ updateField={updateField}
1673
+ tooltip={
1674
+ <Tooltip style={{ textTransform: 'none' }}>
1675
+ <Tooltip.Target>
1676
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1677
+ </Tooltip.Target>
1678
+ <Tooltip.Content>
1679
+ <p>Any value below the cut-off value is included in a special "less than" category. This option supports special conditions like suppressed data.</p>
1680
+ </Tooltip.Content>
1681
+ </Tooltip>
1682
+ }
1683
+ />
1349
1684
  </>
1350
1685
  )}
1351
- {(config.orientation === 'horizontal' && config.yAxis.labelPlacement !== 'On Bar') &&
1352
- <TextField type="number" value={config.barHeight || '25'} fieldName="barHeight" label="Bar Thickness" updateField={updateField} min="15"/>
1353
- }
1354
- {((config.visualizationType === 'Bar' && config.orientation !== 'horizontal') || config.visualizationType === 'Combo') &&
1355
- <TextField value={config.barThickness} type="number" fieldName="barThickness" label="Bar Thickness" updateField={updateField}/>
1356
- }
1357
-
1358
- {config.visualizationType === "Spark Line" &&
1359
- <div className="cove-accordion__panel-section checkbox-group">
1360
- <CheckBox value={config.visual?.border} section="visual" fieldName="border" label="Display Border" updateField={updateField} />
1361
- <CheckBox value={config.visual?.borderColorTheme} section="visual" fieldName="borderColorTheme" label="Use Border Color Theme" updateField={updateField} />
1362
- <CheckBox value={config.visual?.accent} section="visual" fieldName="accent" label="Use Accent Style" updateField={updateField} />
1363
- <CheckBox value={config.visual?.background} section="visual" fieldName="background" label="Use Theme Background Color" updateField={updateField} />
1364
- <CheckBox value={config.visual?.hideBackgroundColor} section="visual" fieldName="hideBackgroundColor" label="Hide Background Color" updateField={updateField} />
1686
+ {config.orientation === 'horizontal' && !config.isLollipopChart && config.yAxis.labelPlacement !== 'On Bar' && <TextField type='number' value={config.barHeight || '25'} fieldName='barHeight' label=' Bar Thickness' updateField={updateField} min='15' />}
1687
+ {((config.visualizationType === 'Bar' && config.orientation !== 'horizontal') || config.visualizationType === 'Combo') && <TextField value={config.barThickness} type='number' fieldName='barThickness' label='Bar Thickness' updateField={updateField} />}
1688
+ {config.orientation === 'horizontal' && <TextField type='number' value={config.barSpace || '20'} fieldName='barSpace' label='Bar Space' updateField={updateField} min='0' />}
1689
+ {(config.visualizationType === 'Bar' || config.visualizationType === 'Line' || config.visualizationType === 'Combo') && <CheckBox value={config.topAxis.hasLine} section='topAxis' fieldName='hasLine' label='Add Top Axis Line' updateField={updateField} />}
1690
+
1691
+ {config.visualizationType === 'Spark Line' && (
1692
+ <div className='cove-accordion__panel-section checkbox-group'>
1693
+ <CheckBox value={config.visual?.border} section='visual' fieldName='border' label='Display Border' updateField={updateField} />
1694
+ <CheckBox value={config.visual?.borderColorTheme} section='visual' fieldName='borderColorTheme' label='Use Border Color Theme' updateField={updateField} />
1695
+ <CheckBox value={config.visual?.accent} section='visual' fieldName='accent' label='Use Accent Style' updateField={updateField} />
1696
+ <CheckBox value={config.visual?.background} section='visual' fieldName='background' label='Use Theme Background Color' updateField={updateField} />
1697
+ <CheckBox value={config.visual?.hideBackgroundColor} section='visual' fieldName='hideBackgroundColor' label='Hide Background Color' updateField={updateField} />
1365
1698
  </div>
1366
- }
1699
+ )}
1700
+
1701
+ {(config.visualizationType === 'Line' || config.visualizationType === 'Combo') && <CheckBox value={config.showLineSeriesLabels} fieldName='showLineSeriesLabels' label='Append Series Name to End of Line Charts' updateField={updateField} />}
1702
+ {(config.visualizationType === 'Line' || config.visualizationType === 'Combo') && config.showLineSeriesLabels && (
1703
+ <CheckBox value={config.colorMatchLineSeriesLabels} fieldName='colorMatchLineSeriesLabels' label='Match Series Color to Name at End of Line Charts' updateField={updateField} />
1704
+ )}
1367
1705
  </AccordionItemPanel>
1368
1706
  </AccordionItem>
1369
1707
 
1370
1708
  <AccordionItem>
1371
1709
  <AccordionItemHeading>
1372
- <AccordionItemButton>
1373
- Data Table
1374
- </AccordionItemButton>
1710
+ <AccordionItemButton>Data Table</AccordionItemButton>
1375
1711
  </AccordionItemHeading>
1376
1712
  <AccordionItemPanel>
1377
- <CheckBox value={config.table.show} section="table" fieldName="show" label="Show Table" updateField={updateField} tooltip={
1378
- <Tooltip style={{ textTransform: 'none' }}>
1379
- <Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }}/></Tooltip.Target>
1380
- <Tooltip.Content>
1381
- <p>Hiding the data table may affect accessibility. An alternate form of accessing visualization data is a 508 requirement.</p>
1382
- </Tooltip.Content>
1383
- </Tooltip>
1384
- }/>
1385
- <TextField
1386
- value={config.table.caption}
1387
- updateField={updateField}
1388
- section='table'
1389
- type='textarea'
1390
- fieldName='caption'
1391
- label='Data Table Caption'
1392
- placeholder=' Data table'
1393
- tooltip={
1394
- <Tooltip style={{textTransform: 'none'}}>
1395
- <Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
1396
- <Tooltip.Content>
1397
- <p>Enter a description of the data table to be read by screen readers.</p>
1398
- </Tooltip.Content>
1399
- </Tooltip>
1400
- }
1401
- />
1402
- <CheckBox value={config.table.limitHeight} section="table" fieldName="limitHeight" label="Limit Table Height" updateField={updateField}/>
1403
- {config.table.limitHeight && (
1404
- <TextField value={config.table.height} section="table" fieldName='height' label='Data Table Height' type="number" min="0" max="500" placeholder='Height(px)' updateField={updateField}/>
1405
- )}
1406
- <CheckBox value={config.table.expanded} section="table" fieldName="expanded" label="Expanded by Default" updateField={updateField}/>
1407
- <CheckBox value={config.table.download} section="table" fieldName="download" label="Display Download Button" updateField={updateField}/>
1408
- <TextField value={config.table.label} section="table" fieldName="label" label="Label" updateField={updateField}/>
1409
- {config.visualizationType !== 'Pie' && <TextField value={config.table.indexLabel} section="table" fieldName="indexLabel" label="Index Column Header" updateField={updateField}/>}
1713
+ <CheckBox
1714
+ value={config.table.show}
1715
+ section='table'
1716
+ fieldName='show'
1717
+ label='Show Table'
1718
+ updateField={updateField}
1719
+ tooltip={
1720
+ <Tooltip style={{ textTransform: 'none' }}>
1721
+ <Tooltip.Target>
1722
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1723
+ </Tooltip.Target>
1724
+ <Tooltip.Content>
1725
+ <p>Hiding the data table may affect accessibility. An alternate form of accessing visualization data is a 508 requirement.</p>
1726
+ </Tooltip.Content>
1727
+ </Tooltip>
1728
+ }
1729
+ />
1730
+ <TextField
1731
+ value={config.table.caption}
1732
+ updateField={updateField}
1733
+ section='table'
1734
+ type='textarea'
1735
+ fieldName='caption'
1736
+ label='Data Table Caption'
1737
+ placeholder=' Data table'
1738
+ tooltip={
1739
+ <Tooltip style={{ textTransform: 'none' }}>
1740
+ <Tooltip.Target>
1741
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1742
+ </Tooltip.Target>
1743
+ <Tooltip.Content>
1744
+ <p>Enter a description of the data table to be read by screen readers.</p>
1745
+ </Tooltip.Content>
1746
+ </Tooltip>
1747
+ }
1748
+ />
1749
+ <CheckBox value={config.table.limitHeight} section='table' fieldName='limitHeight' label='Limit Table Height' updateField={updateField} />
1750
+ {config.table.limitHeight && <TextField value={config.table.height} section='table' fieldName='height' label='Data Table Height' type='number' min='0' max='500' placeholder='Height(px)' updateField={updateField} />}
1751
+ <CheckBox value={config.table.expanded} section='table' fieldName='expanded' label='Expanded by Default' updateField={updateField} />
1752
+ <CheckBox value={config.table.download} section='table' fieldName='download' label='Display Download Button' updateField={updateField} />
1753
+ <CheckBox value={config.table.showDownloadUrl} section='table' fieldName='showDownloadUrl' label='Display Link to Dataset' updateField={updateField} />
1754
+ {/* <CheckBox value={config.table.showDownloadImgButton} section='table' fieldName='showDownloadImgButton' label='Display Image Button' updateField={updateField} /> */}
1755
+ {/* <CheckBox value={config.table.showDownloadPdfButton} section='table' fieldName='showDownloadPdfButton' label='Display PDF Button' updateField={updateField} /> */}
1756
+ <TextField value={config.table.label} section='table' fieldName='label' label='Label' updateField={updateField} />
1757
+ {config.visualizationType !== 'Pie' && <TextField value={config.table.indexLabel} section='table' fieldName='indexLabel' label='Index Column Header' updateField={updateField} />}
1410
1758
  </AccordionItemPanel>
1411
1759
  </AccordionItem>
1412
1760
  </Accordion>
1413
1761
  </form>
1414
- {config.type !== 'Spark Line' &&
1415
- <AdvancedEditor loadConfig={updateConfig} state={config} convertStateToConfig={convertStateToConfig} />
1416
- }
1762
+ {config.type !== 'Spark Line' && <AdvancedEditor loadConfig={updateConfig} state={config} convertStateToConfig={convertStateToConfig} />}
1417
1763
  </section>
1418
1764
  </section>
1419
1765
  </ErrorBoundary>