@cdc/core 4.24.10 → 4.24.12

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 (62) hide show
  1. package/components/AdvancedEditor/AdvancedEditor.tsx +17 -13
  2. package/components/Alert/components/Alert.tsx +39 -8
  3. package/components/DataTable/DataTable.tsx +31 -10
  4. package/components/DataTable/components/ExpandCollapse.tsx +1 -1
  5. package/components/DataTable/components/SortIcon/sort-icon.css +15 -0
  6. package/components/DataTable/data-table.css +4 -22
  7. package/components/DataTable/helpers/boxplotCellMatrix.tsx +19 -14
  8. package/components/DataTable/helpers/getChartCellValue.ts +25 -7
  9. package/components/EditorPanel/ColumnsEditor.tsx +81 -36
  10. package/components/EditorPanel/DataTableEditor.tsx +62 -56
  11. package/components/EditorPanel/FieldSetWrapper.tsx +2 -2
  12. package/components/EditorPanel/Inputs.tsx +26 -16
  13. package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +43 -56
  14. package/components/Filters/Filters.tsx +16 -11
  15. package/components/Footnotes/FootnotesStandAlone.tsx +17 -4
  16. package/components/Layout/components/Sidebar/components/sidebar.styles.scss +0 -4
  17. package/components/Layout/components/Visualization/visualizations.scss +1 -1
  18. package/components/Legend/Legend.Gradient.tsx +50 -35
  19. package/components/Loader/Loader.tsx +10 -5
  20. package/components/MultiSelect/MultiSelect.tsx +56 -33
  21. package/components/MultiSelect/multiselect.styles.css +20 -7
  22. package/components/NestedDropdown/NestedDropdown.tsx +55 -32
  23. package/components/NestedDropdown/nesteddropdown.styles.css +26 -13
  24. package/components/Table/Table.tsx +102 -34
  25. package/components/Table/components/Row.tsx +1 -1
  26. package/components/_stories/DataTable.stories.tsx +14 -0
  27. package/components/_stories/Filters.stories.tsx +57 -0
  28. package/components/_stories/_mocks/DataTable/no-data.json +108 -0
  29. package/components/inputs/{InputToggle.jsx → InputToggle.tsx} +35 -29
  30. package/components/ui/Icon.tsx +19 -6
  31. package/dist/cove-main.css +26 -57
  32. package/dist/cove-main.css.map +1 -1
  33. package/helpers/DataTransform.ts +2 -1
  34. package/helpers/cove/{number.js → number.ts} +25 -11
  35. package/helpers/fetchRemoteData.js +32 -37
  36. package/helpers/formatConfigBeforeSave.ts +1 -0
  37. package/helpers/gatherQueryParams.ts +2 -3
  38. package/helpers/queryStringUtils.ts +16 -1
  39. package/helpers/useDataVizClasses.ts +44 -21
  40. package/helpers/ver/versionNeedsUpdate.ts +2 -0
  41. package/helpers/viewports.ts +8 -7
  42. package/package.json +2 -2
  43. package/styles/_button-section.scss +1 -1
  44. package/styles/_global-variables.scss +9 -4
  45. package/styles/_global.scss +21 -22
  46. package/styles/_reset.scss +0 -12
  47. package/styles/filters.scss +0 -22
  48. package/styles/v2/base/_reset.scss +0 -7
  49. package/styles/v2/components/editor.scss +0 -4
  50. package/styles/v2/components/icon.scss +1 -1
  51. package/types/Axis.ts +2 -0
  52. package/types/BoxPlot.ts +5 -3
  53. package/types/Color.ts +1 -1
  54. package/types/Legend.ts +1 -2
  55. package/types/MarkupInclude.ts +1 -0
  56. package/types/Runtime.ts +3 -1
  57. package/types/Series.ts +8 -1
  58. package/types/Table.ts +1 -1
  59. package/types/Version.ts +1 -0
  60. package/types/Visualization.ts +7 -8
  61. package/components/ui/Select.jsx +0 -30
  62. package/helpers/getGradientLegendWidth.ts +0 -15
@@ -6,6 +6,7 @@ import { FilterFunction, JsonEditor, UpdateFunction } from 'json-edit-react'
6
6
  import { formatConfigBeforeSave as stripConfig } from '../../helpers/formatConfigBeforeSave'
7
7
  import './advanced-editor-styles.css'
8
8
  import _ from 'lodash'
9
+ import Tooltip from '../ui/Tooltip'
9
10
 
10
11
  export const AdvancedEditor = ({ loadConfig, config, convertStateToConfig, onExpandCollapse = () => {} }) => {
11
12
  const [advancedToggle, _setAdvancedToggle] = useState(false)
@@ -37,7 +38,11 @@ export const AdvancedEditor = ({ loadConfig, config, convertStateToConfig, onExp
37
38
  chart: ['Charts', 'https://www.cdc.gov/wcms/4.0/cdc-wp/data-presentation/bar-chart.html', <ChartIcon />],
38
39
  dashboard: ['Dashboard', 'https://www.cdc.gov/wcms/4.0/cdc-wp/data-presentation/bar-chart.html', <ChartIcon />],
39
40
  map: ['Maps', 'https://www.cdc.gov/wcms/4.0/cdc-wp/data-presentation/data-map.html', <MapIcon />],
40
- 'markup-include': ['Markup Include', 'https://www.cdc.gov/wcms/4.0/cdc-wp/data-presentation/Markup-Include.html', <MarkupIncludeIcon />]
41
+ 'markup-include': [
42
+ 'Markup Include',
43
+ 'https://www.cdc.gov/wcms/4.0/cdc-wp/data-presentation/Markup-Include.html',
44
+ <MarkupIncludeIcon />
45
+ ]
41
46
  }
42
47
 
43
48
  if (!config.type) return <></>
@@ -63,25 +68,24 @@ export const AdvancedEditor = ({ loadConfig, config, convertStateToConfig, onExp
63
68
  </div>
64
69
  </section>
65
70
  <p className='pb-2'>
66
- This tool displays the actual <acronym title='JavaScript Object Notation'>JSON</acronym> configuration that is generated by this editor and allows you to edit properties directly and apply them.
71
+ This tool displays the actual <acronym title='JavaScript Object Notation'>JSON</acronym> configuration
72
+ that is generated by this editor and allows you to edit properties directly and apply them.
67
73
  </p>
74
+ <JsonEditor
75
+ className='advanced-json-editor'
76
+ data={configTextboxValue}
77
+ onUpdate={onUpdate}
78
+ rootName=''
79
+ collapse={collapseFields}
80
+ />
68
81
  <button
69
- className='btn '
70
- onClick={() => {
71
- navigator.clipboard.writeText(JSON.stringify(configTextboxValue))
72
- }}
73
- >
74
- Copy to Clipboard
75
- </button>
76
- <JsonEditor className='advanced-json-editor' data={configTextboxValue} onUpdate={onUpdate} rootName='' collapse={collapseFields} />
77
- <button
78
- className='btn full-width'
82
+ className='btn btn-success m-2 p-2'
79
83
  onClick={() => {
80
84
  loadConfig(configTextboxValue)
81
85
  setAdvancedToggle(!advancedToggle)
82
86
  }}
83
87
  >
84
- Apply
88
+ Apply Configuration Changes
85
89
  </button>
86
90
  </React.Fragment>
87
91
  )}
@@ -1,7 +1,7 @@
1
1
  import Icon from '../../ui/Icon'
2
2
 
3
3
  import DOMPurify from 'dompurify'
4
- import React from 'react'
4
+ import React, { useEffect } from 'react'
5
5
 
6
6
  import './Alert.styles.css'
7
7
 
@@ -14,10 +14,34 @@ type AlertProps = {
14
14
  iconSize?: number
15
15
  // heading for the alert box
16
16
  heading?: string
17
+ // dismiss function
18
+ onDismiss?: Function
19
+ // make the alert dismiss on it's own
20
+ autoDismiss?: boolean
21
+ // set seconds until autoDismiss, default is 5 seconds
22
+ secondsBeforeDismiss?: number
23
+ // provide option for non dismissable alert
24
+ showCloseButton?: boolean
17
25
  }
18
26
 
19
- const Alert: React.FC<AlertProps> = ({ type = 'info', message = '', iconSize = 21, heading }) => {
27
+ const Alert: React.FC<AlertProps> = ({
28
+ type = 'info',
29
+ message = '',
30
+ iconSize = 21,
31
+ heading,
32
+ onDismiss,
33
+ autoDismiss,
34
+ secondsBeforeDismiss = 5,
35
+ showCloseButton = true
36
+ }) => {
20
37
  // sanitize the text for setting dangerouslySetInnerHTML
38
+
39
+ useEffect(() => {
40
+ if (autoDismiss) {
41
+ setTimeout(() => onDismiss(), secondsBeforeDismiss * 1000)
42
+ }
43
+ }, [])
44
+
21
45
  const sanitizedData = () => ({
22
46
  __html: DOMPurify.sanitize(message)
23
47
  })
@@ -26,12 +50,19 @@ const Alert: React.FC<AlertProps> = ({ type = 'info', message = '', iconSize = 2
26
50
  const styleResets = { width: 'unset', height: 'unset', paddingRight: '5px' }
27
51
 
28
52
  return (
29
- <div className={`alert alert-${type} p-1`} role='alert'>
30
- {heading && <h4 className='alert-heading'>{heading}</h4>}
31
- {type === 'success' && <Icon display='check' size={iconSize} />}
32
- {type === 'danger' && <Icon display='warningCircle' size={iconSize} />}
33
- {type === 'info' && <Icon display='info' size={iconSize} />}
34
- <span dangerouslySetInnerHTML={sanitizedData()} />
53
+ <div className={`alert alert-${type} p-1 d-flex justify-content-between`} role='alert'>
54
+ <div className='d-flex'>
55
+ {heading && <h4 className='alert-heading'>{heading}</h4>}
56
+ {type === 'success' && <Icon display='check' size={iconSize} />}
57
+ {type === 'danger' && <Icon display='warningCircle' size={iconSize} />}
58
+ {type === 'info' && <Icon display='info' size={iconSize} />}
59
+ <span dangerouslySetInnerHTML={sanitizedData()} />
60
+ </div>
61
+ {showCloseButton && (
62
+ <button type='button' className='close pl-5' aria-label='Close' onClick={() => onDismiss()}>
63
+ X
64
+ </button>
65
+ )}
35
66
  </div>
36
67
  )
37
68
  }
@@ -22,6 +22,7 @@ import { Column } from '../../types/Column'
22
22
  import { pivotData } from '../../helpers/pivotData'
23
23
  import { isLegendWrapViewport } from '@cdc/core/helpers/viewports'
24
24
  import './data-table.css'
25
+ import _ from 'lodash'
25
26
 
26
27
  export type DataTableProps = {
27
28
  applyLegendToRow?: Function
@@ -73,9 +74,14 @@ const DataTable = (props: DataTableProps) => {
73
74
  const runtimeData = useMemo(() => {
74
75
  const data = removeNullColumns(parentRuntimeData)
75
76
  if (config.table.pivot) {
77
+ const excludeColumns = Object.values(config.columns || {})
78
+ .filter(column => column.dataTable === false)
79
+ .map(col => col.name)
76
80
  const { columnName, valueColumns } = config.table.pivot
77
81
  if (columnName && valueColumns) {
78
- return pivotData(data, columnName, valueColumns)
82
+ // remove excluded columns so that they aren't included in the pivot calculation
83
+ const _data = data.map(row => _.omit(row, excludeColumns))
84
+ return pivotData(_data, columnName, valueColumns)
79
85
  }
80
86
  }
81
87
  return data
@@ -84,7 +90,7 @@ const DataTable = (props: DataTableProps) => {
84
90
  const [expanded, setExpanded] = useState(expandDataTable)
85
91
 
86
92
  const [sortBy, setSortBy] = useState<any>({
87
- column: config.type === 'map' ? 'geo' : 'date',
93
+ column: '',
88
94
  asc: false,
89
95
  colIndex: null
90
96
  })
@@ -196,10 +202,11 @@ const DataTable = (props: DataTableProps) => {
196
202
  : config.visualizationType === 'Pie'
197
203
  ? [config.yAxis.dataKey]
198
204
  : config.visualizationType === 'Box Plot'
199
- ? Object.entries(config.boxplot.tableData[0])
205
+ ? config?.boxplot?.plots?.[0] ? Object.entries(config.boxplot.plots[0]) : []
200
206
  : config.runtime?.seriesKeys),
201
207
  [config.runtime?.seriesKeys]) // eslint-disable-line
202
208
 
209
+ const hasNoData = runtimeData.length === 0
203
210
  if (config.visualizationType !== 'Box Plot') {
204
211
  const getDownloadData = () => {
205
212
  // only use fullGeoName on County maps and no other
@@ -237,17 +244,28 @@ const DataTable = (props: DataTableProps) => {
237
244
  </MediaControls.Section>
238
245
  )
239
246
  }
247
+ const getClassNames = (): string => {
248
+ const classes = ['data-table-container']
249
+ const isBrushActive = config?.brush?.active && config.legend?.position !== 'bottom'
250
+
251
+ if (isBrushActive) {
252
+ classes.push('brush-active')
253
+ }
254
+
255
+ classes.push(viewport)
256
+
257
+ const downloadLinkClass = !config.table.showDownloadLinkBelow ? 'download-link-above' : ''
258
+ if (downloadLinkClass) {
259
+ classes.push(downloadLinkClass)
260
+ }
261
+
262
+ return classes.join(' ')
263
+ }
240
264
 
241
265
  return (
242
266
  <ErrorBoundary component='DataTable'>
243
267
  {!config.table.showDownloadLinkBelow && <TableMediaControls />}
244
- <section
245
- id={tabbingId.replace('#', '')}
246
- className={`data-table-container ${viewport} ${
247
- !config.table.showDownloadLinkBelow ? 'download-link-above' : ''
248
- }`}
249
- aria-label={accessibilityLabel}
250
- >
268
+ <section id={tabbingId.replace('#', '')} className={getClassNames()} aria-label={accessibilityLabel}>
251
269
  <SkipTo skipId={skipId} skipMessage='Skip Data Table' />
252
270
  {config.table.collapsible !== false && (
253
271
  <ExpandCollapse
@@ -263,6 +281,7 @@ const DataTable = (props: DataTableProps) => {
263
281
  preliminaryData={config.preliminaryData}
264
282
  viewport={viewport}
265
283
  wrapColumns={wrapColumns}
284
+ noData={hasNoData}
266
285
  childrenMatrix={
267
286
  config.type === 'map'
268
287
  ? mapCellMatrix({ rows, wrapColumns, ...props, runtimeData, viewport })
@@ -306,6 +325,7 @@ const DataTable = (props: DataTableProps) => {
306
325
  viewport={viewport}
307
326
  wrapColumns={wrapColumns}
308
327
  childrenMatrix={regionCellMatrix({ config })}
328
+ noData={hasNoData}
309
329
  tableName={config.visualizationType}
310
330
  caption='Table of the highlighted regions in the visualization'
311
331
  headContent={
@@ -343,6 +363,7 @@ const DataTable = (props: DataTableProps) => {
343
363
  viewport={viewport}
344
364
  wrapColumns={wrapColumns}
345
365
  childrenMatrix={boxplotCellMatrix({ rows: tableData, config })}
366
+ noData={hasNoData}
346
367
  tableName={config.visualizationType}
347
368
  caption={caption}
348
369
  stickyHeader
@@ -2,7 +2,7 @@ import Icon from '../../ui/Icon'
2
2
  import { fontSizes } from '../../../helpers/cove/fontSettings'
3
3
 
4
4
  const ExpandCollapse = ({ expanded, setExpanded, tableTitle, fontSize, viewport }) => {
5
- const titleFontSize = ['sm', 'xs', 'xxs'].includes(viewport) ? '13px' : `${fontSizes[fontSize]}px`
5
+ const titleFontSize = ['xs', 'xxs'].includes(viewport) ? '13px' : `${fontSizes[fontSize]}px`
6
6
  return (
7
7
  <div
8
8
  style={{ fontSize: titleFontSize }}
@@ -19,3 +19,18 @@
19
19
  top: 0.5rem;
20
20
  }
21
21
  }
22
+
23
+ @media (max-width: 576px) {
24
+ .sort-icon {
25
+ :is(svg) {
26
+ width: 0.9rem;
27
+ height: 0.9rem;
28
+ }
29
+ .up {
30
+ bottom: 0.3rem;
31
+ }
32
+ .down {
33
+ top: 0.3rem;
34
+ }
35
+ }
36
+ }
@@ -211,33 +211,15 @@ table.data-table {
211
211
  }
212
212
  button {
213
213
  background: var(--mediumGray);
214
- padding: 0.6rem 0.8rem;
215
214
  &:hover {
216
215
  background: lighten(var(--mediumGray), 5%);
217
216
  }
218
217
  }
219
- button.btn-next {
220
- &::before {
221
- content: ' ';
222
- background-image: url(../assets/icon-caret-filled-up.svg);
223
- background-size: 10px 5px;
224
- width: 10px;
225
- height: 5px;
226
- display: block;
227
- transform: rotate(90deg);
228
- }
229
- }
230
- button.btn-prev {
231
- &::before {
232
- content: ' ';
233
- background-image: url(../assets/icon-caret-filled-up.svg);
234
- background-size: 10px 5px;
235
- width: 10px;
236
- height: 5px;
237
- display: block;
238
- transform: rotate(-90deg);
239
- }
218
+
219
+ button.btn svg {
220
+ margin: 0px 0 3px 0;
240
221
  }
222
+
241
223
  button[disabled] {
242
224
  background: var(--mediumGray);
243
225
  opacity: 0.3;
@@ -16,9 +16,9 @@ const boxplotCellMatrix = ({ rows, config }): CellMatrix => {
16
16
  columnThirdQuartile: labels.q3,
17
17
  columnOutliers: labels.outliers,
18
18
  values: labels.values,
19
- columnTotal: labels.total,
19
+ columnCount: labels.count,
20
20
  columnSd: 'Standard Deviation',
21
- nonOutlierValues: 'Non Outliers',
21
+ columnNonOutliers: 'Non Outliers',
22
22
  columnLowerBounds: labels.lowerBounds,
23
23
  columnUpperBounds: labels.upperBounds
24
24
  }
@@ -28,30 +28,35 @@ const boxplotCellMatrix = ({ rows, config }): CellMatrix => {
28
28
  return resolvedName
29
29
  }
30
30
  let resolveCell = (rowid, plot) => {
31
- if (Number(rowid) === 0) return true
32
- if (Number(rowid) === 1) return plot.columnMax
33
- if (Number(rowid) === 2) return plot.columnThirdQuartile
34
- if (Number(rowid) === 3) return plot.columnMedian
35
- if (Number(rowid) === 4) return plot.columnFirstQuartile
36
- if (Number(rowid) === 5) return plot.columnMin
37
- if (Number(rowid) === 6) return plot.columnTotal
38
- if (Number(rowid) === 7) return plot.columnSd
39
- if (Number(rowid) === 8) return plot.columnMean
40
- if (Number(rowid) === 9) return plot.columnOutliers.length > 0 ? plot.columnOutliers.toString() : '-'
41
- if (Number(rowid) === 10) return plot.values.length > 0 ? plot.values.toString() : '-'
31
+ if (Number(rowid) === 0) return plot.columnMax
32
+ if (Number(rowid) === 1) return plot.columnThirdQuartile
33
+ if (Number(rowid) === 2) return plot.columnMedian
34
+ if (Number(rowid) === 3) return plot.columnFirstQuartile
35
+ if (Number(rowid) === 4) return plot.columnMin
36
+ if (Number(rowid) === 5) return plot.columnCount
37
+ if (Number(rowid) === 6) return plot.columnSd
38
+ if (Number(rowid) === 7) return plot.columnMean
39
+ if (Number(rowid) === 8) return plot.columnIqr
40
+ if (Number(rowid) === 9) return plot.values.length > 0 ? plot.values.toString() : '-'
41
+ if (Number(rowid) === 10) return plot.columnLowerBounds
42
+ if (Number(rowid) === 11) return plot.columnUpperBounds
43
+ if (Number(rowid) === 12) return plot.columnOutliers.length > 0 ? plot.columnOutliers.toString() : '-'
44
+ if (Number(rowid) === 13) return plot.columnNonOutliers.length > 0 ? plot.columnNonOutliers.toString() : '-'
42
45
  return <p>-</p>
43
46
  }
44
47
  // get list of data keys for each row
45
48
  let dataKeys = rows.map(row => {
46
49
  return row[0]
47
50
  })
51
+
48
52
  let columns = ['Measures', ...config.boxplot.categories]
49
53
  dataKeys.shift() // remove index 0 // we did header column separately
54
+
50
55
  return dataKeys.map((rowkey, index) => {
51
56
  return columns.map((column, colnum) => {
52
57
  let cellValue
53
58
  if (column === 'Measures') {
54
- let labelValue = index > 0 ? resolveName(rowkey) : ''
59
+ let labelValue = resolveName(rowkey)
55
60
  cellValue = <>{labelValue}</>
56
61
  } else {
57
62
  cellValue = resolveCell(index, config.boxplot.plots[colnum - 1])
@@ -1,5 +1,5 @@
1
1
  import { parseDate, formatDate } from '@cdc/core/helpers/cove/date'
2
- import { formatNumber } from '@cdc/core/helpers/cove/number'
2
+ import { formatNumber } from '../../../helpers/cove/number'
3
3
  import { TableConfig } from '../types/TableConfig'
4
4
 
5
5
  // if its additional column, return formatting params
@@ -29,10 +29,18 @@ export const getChartCellValue = (row: string, column: string, config: TableConf
29
29
 
30
30
  const rowObj = runtimeData[row]
31
31
  let cellValue // placeholder for formatting below
32
- let labelValue = rowObj[column] // just raw X axis string
32
+ const labelValue = rowObj[column] // just raw X axis string
33
33
  if (column === config.xAxis?.dataKey) {
34
- // not the prettiest, but helper functions work nicely here.
35
- cellValue = config.xAxis?.type === 'date' ? formatDate(config.table?.dateDisplayFormat || config.xAxis?.dateDisplayFormat, parseDate(config.xAxis?.dateParseFormat, labelValue)) : labelValue
34
+ const { type, dateDisplayFormat, dateParseFormat } = config.xAxis || {}
35
+ const dateFormat = config.table?.dateDisplayFormat || dateDisplayFormat
36
+
37
+ if (type === 'date' || type === 'date-time') {
38
+ cellValue = formatDate(dateFormat, parseDate(dateParseFormat, labelValue))
39
+ } else if (type === 'continuous') {
40
+ cellValue = formatNumber(runtimeData[row][column], 'bottom', false, config)
41
+ } else {
42
+ cellValue = labelValue
43
+ }
36
44
  } else {
37
45
  let resolvedAxis = 'left'
38
46
  let leftAxisItems = config.series ? config.series.filter(item => item?.axis === 'Left') : []
@@ -48,9 +56,13 @@ export const getChartCellValue = (row: string, column: string, config: TableConf
48
56
 
49
57
  let addColParams = isAdditionalColumn(column, config)
50
58
  if (addColParams) {
51
- cellValue = config.dataFormat ? formatNumber(runtimeData[row][column], resolvedAxis, false, config, addColParams) : runtimeData[row][column]
59
+ cellValue = config.dataFormat
60
+ ? formatNumber(runtimeData[row][column], resolvedAxis, false, config, addColParams)
61
+ : runtimeData[row][column]
52
62
  } else {
53
- cellValue = config.dataFormat ? formatNumber(runtimeData[row][column], resolvedAxis, false, config) : runtimeData[row][column]
63
+ cellValue = config.dataFormat
64
+ ? formatNumber(runtimeData[row][column], resolvedAxis, false, config)
65
+ : runtimeData[row][column]
54
66
  }
55
67
  }
56
68
 
@@ -63,7 +75,13 @@ export const getChartCellValue = (row: string, column: string, config: TableConf
63
75
  const barSeriesExist = config.runtime?.barSeriesKeys?.includes(column)
64
76
  const lineSeriesExist = config.runtime?.lineSeriesKeys?.includes(column)
65
77
  const showSymbol = config.general.showSuppressedSymbol
66
- if (isValueMatch && isColumnMatch && pd.displayTable && pd.type === 'suppression' && config.visualizationSubType !== 'stacked') {
78
+ if (
79
+ isValueMatch &&
80
+ isColumnMatch &&
81
+ pd.displayTable &&
82
+ pd.type === 'suppression' &&
83
+ config.visualizationSubType !== 'stacked'
84
+ ) {
67
85
  switch (config.visualizationType) {
68
86
  case 'Combo':
69
87
  cellValue = barSeriesExist && showSymbol ? pd.iconCode : lineSeriesExist && showSymbol ? pd.lineCode : ''
@@ -1,6 +1,6 @@
1
1
  import Tooltip from '../ui/Tooltip'
2
2
  import Icon from '../ui/Icon'
3
- import { TextField } from './Inputs'
3
+ import { Select, TextField } from './Inputs'
4
4
  import { Visualization } from '../../types/Visualization'
5
5
  import { UpdateFieldFunc } from '../../types/UpdateFieldFunc'
6
6
  import { Column } from '../../types/Column'
@@ -16,7 +16,13 @@ interface ColumnsEditorProps {
16
16
 
17
17
  type OpenControls = [Record<string, boolean>, Function] // useState type
18
18
 
19
- const FieldSet: React.FC<ColumnsEditorProps & { colKey: string; controls: OpenControls }> = ({ config, deleteColumn, updateField, colKey, controls }) => {
19
+ const FieldSet: React.FC<ColumnsEditorProps & { colKey: string; controls: OpenControls }> = ({
20
+ config,
21
+ deleteColumn,
22
+ updateField,
23
+ colKey,
24
+ controls
25
+ }) => {
20
26
  const [openControls, setOpenControls] = controls
21
27
 
22
28
  const editColumn = (key, value) => {
@@ -63,43 +69,69 @@ const FieldSet: React.FC<ColumnsEditorProps & { colKey: string; controls: OpenCo
63
69
  const colName = config.columns[colKey]?.name
64
70
 
65
71
  return (
66
- <FieldSetWrapper fieldName={colName} fieldKey={colKey} fieldType='Column' controls={controls} deleteField={() => deleteColumn(colKey)}>
67
- <label>
68
- <span className='edit-label column-heading'>Column</span>
69
- <select
70
- value={config.columns[colKey] ? config.columns[colKey].name : undefined}
71
- onChange={event => {
72
- changeName(event.target.value)
73
- }}
74
- >
75
- {['-Select-', ...getColumns()].map(option => (
76
- <option key={option}>{option}</option>
77
- ))}
78
- </select>
79
- </label>
72
+ <FieldSetWrapper
73
+ fieldName={colName}
74
+ fieldKey={colKey}
75
+ fieldType='Column'
76
+ controls={controls}
77
+ deleteField={() => deleteColumn(colKey)}
78
+ >
79
+ <Select
80
+ label='Column'
81
+ value={config.columns[colKey]?.name}
82
+ fieldName='name'
83
+ section={'columns'}
84
+ initial={'-Select-'}
85
+ options={getColumns()}
86
+ updateField={(_section, _subsection, _fieldName, value) => changeName(value)}
87
+ />
80
88
  {config.type !== 'table' && (
81
- <label>
82
- <span className='edit-label column-heading'>Associate to Series</span>
83
- <select
84
- value={config.columns[colKey] ? config.columns[colKey].series : ''}
85
- onChange={event => {
86
- editColumn('series', event.target.value)
87
- }}
88
- >
89
- <option value=''>Select series</option>
90
- {(config.series || []).map(series => (
91
- <option key={series.dataKey}>{series.dataKey}</option>
92
- ))}
93
- </select>
94
- </label>
89
+ <Select
90
+ label='Associate to Series'
91
+ value={config.columns[colKey]?.series}
92
+ fieldName={'series'}
93
+ section='columns'
94
+ initial={'Select series'}
95
+ options={config.series?.map(series => series.dataKey) || []}
96
+ updateField={(_section, _subsection, _fieldName, value) => editColumn('series', value)}
97
+ />
95
98
  )}
96
99
 
97
- <TextField value={config.columns[colKey].label} section='columns' subsection={colKey} fieldName='label' label='Label' updateField={updateField} />
100
+ <TextField
101
+ value={config.columns[colKey].label}
102
+ section='columns'
103
+ subsection={colKey}
104
+ fieldName='label'
105
+ label='Label'
106
+ updateField={updateField}
107
+ />
98
108
  <ul className='column-edit'>
99
109
  <li className='three-col'>
100
- <TextField value={config.columns[colKey].prefix} section='columns' subsection={colKey} fieldName='prefix' label='Prefix' updateField={updateField} />
101
- <TextField value={config.columns[colKey].suffix} section='columns' subsection={colKey} fieldName='suffix' label='Suffix' updateField={updateField} />
102
- <TextField type='number' value={config.columns[colKey].roundToPlace} section='columns' subsection={colKey} fieldName='roundToPlace' label='Round' updateField={updateField} />
110
+ <TextField
111
+ value={config.columns[colKey].prefix}
112
+ section='columns'
113
+ subsection={colKey}
114
+ fieldName='prefix'
115
+ label='Prefix'
116
+ updateField={updateField}
117
+ />
118
+ <TextField
119
+ value={config.columns[colKey].suffix}
120
+ section='columns'
121
+ subsection={colKey}
122
+ fieldName='suffix'
123
+ label='Suffix'
124
+ updateField={updateField}
125
+ />
126
+ <TextField
127
+ type='number'
128
+ value={config.columns[colKey].roundToPlace}
129
+ section='columns'
130
+ subsection={colKey}
131
+ fieldName='roundToPlace'
132
+ label='Round'
133
+ updateField={updateField}
134
+ />
103
135
  </li>
104
136
  <li>
105
137
  <label className='checkbox'>
@@ -202,7 +234,13 @@ const FieldSet: React.FC<ColumnsEditorProps & { colKey: string; controls: OpenCo
202
234
  </ul>
203
235
  <label>
204
236
  <span className='edit-label column-heading'>Order</span>
205
- <input onWheel={e => e.currentTarget.blur()} type='number' min='1' value={config.columns[colKey].order} onChange={e => updateField('columns', colKey, 'order', parseInt(e.target.value))} />
237
+ <input
238
+ onWheel={e => e.currentTarget.blur()}
239
+ type='number'
240
+ min='1'
241
+ value={config.columns[colKey].order}
242
+ onChange={e => updateField('columns', colKey, 'order', parseInt(e.target.value))}
243
+ />
206
244
  </label>
207
245
  </FieldSetWrapper>
208
246
  )
@@ -252,7 +290,14 @@ const ColumnsEditor: React.FC<ColumnsEditorProps> = ({ config, updateField, dele
252
290
  </span>
253
291
  </label>
254
292
  {additionalColumns.map((val, i) => (
255
- <FieldSet key={val + i} controls={openControls} config={config} deleteColumn={deleteColumn} updateField={updateField} colKey={val} />
293
+ <FieldSet
294
+ key={val + i}
295
+ controls={openControls}
296
+ config={config}
297
+ deleteColumn={deleteColumn}
298
+ updateField={updateField}
299
+ colKey={val}
300
+ />
256
301
  ))}
257
302
  <button
258
303
  className={'btn btn-primary'}