@cdc/core 4.24.10 → 4.24.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/AdvancedEditor/AdvancedEditor.tsx +17 -13
- package/components/Alert/components/Alert.tsx +34 -8
- package/components/DataTable/DataTable.tsx +12 -2
- package/components/DataTable/data-table.css +4 -22
- package/components/DataTable/helpers/boxplotCellMatrix.tsx +14 -13
- package/components/DataTable/helpers/getChartCellValue.ts +23 -5
- package/components/EditorPanel/ColumnsEditor.tsx +81 -36
- package/components/EditorPanel/DataTableEditor.tsx +33 -33
- package/components/EditorPanel/FieldSetWrapper.tsx +2 -2
- package/components/EditorPanel/Inputs.tsx +26 -16
- package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +30 -55
- package/components/Filters/Filters.tsx +12 -4
- package/components/Layout/components/Sidebar/components/sidebar.styles.scss +0 -4
- package/components/Layout/components/Visualization/visualizations.scss +1 -1
- package/components/Legend/Legend.Gradient.tsx +49 -34
- package/components/MultiSelect/MultiSelect.tsx +85 -62
- package/components/MultiSelect/multiselect.styles.css +10 -7
- package/components/NestedDropdown/NestedDropdown.tsx +40 -20
- package/components/NestedDropdown/nesteddropdown.styles.css +15 -13
- package/components/Table/Table.tsx +102 -34
- package/components/_stories/DataTable.stories.tsx +14 -0
- package/components/_stories/Filters.stories.tsx +57 -0
- package/components/_stories/_mocks/DataTable/no-data.json +108 -0
- package/components/ui/Icon.tsx +19 -6
- package/dist/cove-main.css +20 -54
- package/dist/cove-main.css.map +1 -1
- package/helpers/DataTransform.ts +2 -1
- package/helpers/cove/{number.js → number.ts} +25 -11
- package/helpers/fetchRemoteData.js +32 -37
- package/helpers/formatConfigBeforeSave.ts +1 -0
- package/helpers/queryStringUtils.ts +6 -0
- package/helpers/useDataVizClasses.ts +42 -20
- package/package.json +2 -2
- package/styles/_button-section.scss +1 -1
- package/styles/_global-variables.scss +3 -3
- package/styles/_global.scss +21 -22
- package/styles/_reset.scss +0 -11
- package/styles/filters.scss +0 -22
- package/styles/v2/base/_reset.scss +0 -7
- package/styles/v2/components/editor.scss +0 -4
- package/styles/v2/components/icon.scss +1 -1
- package/types/Axis.ts +2 -0
- package/types/BoxPlot.ts +5 -3
- package/types/Color.ts +1 -1
- package/types/Legend.ts +1 -2
- package/types/MarkupInclude.ts +1 -0
- package/types/Runtime.ts +3 -1
- package/types/Series.ts +8 -1
- package/types/Table.ts +1 -1
- package/types/Visualization.ts +7 -8
- package/components/ui/Select.jsx +0 -30
- 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': [
|
|
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
|
|
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,31 @@ 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
|
|
17
23
|
}
|
|
18
24
|
|
|
19
|
-
const Alert: React.FC<AlertProps> = ({
|
|
25
|
+
const Alert: React.FC<AlertProps> = ({
|
|
26
|
+
type = 'info',
|
|
27
|
+
message = '',
|
|
28
|
+
iconSize = 21,
|
|
29
|
+
heading,
|
|
30
|
+
onDismiss,
|
|
31
|
+
autoDismiss,
|
|
32
|
+
secondsBeforeDismiss = 5
|
|
33
|
+
}) => {
|
|
20
34
|
// sanitize the text for setting dangerouslySetInnerHTML
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (autoDismiss) {
|
|
38
|
+
setTimeout(() => onDismiss(), secondsBeforeDismiss * 1000)
|
|
39
|
+
}
|
|
40
|
+
}, [])
|
|
41
|
+
|
|
21
42
|
const sanitizedData = () => ({
|
|
22
43
|
__html: DOMPurify.sanitize(message)
|
|
23
44
|
})
|
|
@@ -26,12 +47,17 @@ const Alert: React.FC<AlertProps> = ({ type = 'info', message = '', iconSize = 2
|
|
|
26
47
|
const styleResets = { width: 'unset', height: 'unset', paddingRight: '5px' }
|
|
27
48
|
|
|
28
49
|
return (
|
|
29
|
-
<div className={`alert alert-${type} p-1`} role='alert'>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
50
|
+
<div className={`alert alert-${type} p-1 d-flex justify-content-between`} role='alert'>
|
|
51
|
+
<div className='d-flex'>
|
|
52
|
+
{heading && <h4 className='alert-heading'>{heading}</h4>}
|
|
53
|
+
{type === 'success' && <Icon display='check' size={iconSize} />}
|
|
54
|
+
{type === 'danger' && <Icon display='warningCircle' size={iconSize} />}
|
|
55
|
+
{type === 'info' && <Icon display='info' size={iconSize} />}
|
|
56
|
+
<span dangerouslySetInnerHTML={sanitizedData()} />
|
|
57
|
+
</div>
|
|
58
|
+
<button type='button' className='close pl-5' aria-label='Close' onClick={() => onDismiss()}>
|
|
59
|
+
X
|
|
60
|
+
</button>
|
|
35
61
|
</div>
|
|
36
62
|
)
|
|
37
63
|
}
|
|
@@ -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
|
-
|
|
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:
|
|
93
|
+
column: '',
|
|
88
94
|
asc: false,
|
|
89
95
|
colIndex: null
|
|
90
96
|
})
|
|
@@ -200,6 +206,7 @@ const DataTable = (props: DataTableProps) => {
|
|
|
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
|
|
@@ -263,6 +270,7 @@ const DataTable = (props: DataTableProps) => {
|
|
|
263
270
|
preliminaryData={config.preliminaryData}
|
|
264
271
|
viewport={viewport}
|
|
265
272
|
wrapColumns={wrapColumns}
|
|
273
|
+
noData={hasNoData}
|
|
266
274
|
childrenMatrix={
|
|
267
275
|
config.type === 'map'
|
|
268
276
|
? mapCellMatrix({ rows, wrapColumns, ...props, runtimeData, viewport })
|
|
@@ -306,6 +314,7 @@ const DataTable = (props: DataTableProps) => {
|
|
|
306
314
|
viewport={viewport}
|
|
307
315
|
wrapColumns={wrapColumns}
|
|
308
316
|
childrenMatrix={regionCellMatrix({ config })}
|
|
317
|
+
noData={hasNoData}
|
|
309
318
|
tableName={config.visualizationType}
|
|
310
319
|
caption='Table of the highlighted regions in the visualization'
|
|
311
320
|
headContent={
|
|
@@ -343,6 +352,7 @@ const DataTable = (props: DataTableProps) => {
|
|
|
343
352
|
viewport={viewport}
|
|
344
353
|
wrapColumns={wrapColumns}
|
|
345
354
|
childrenMatrix={boxplotCellMatrix({ rows: tableData, config })}
|
|
355
|
+
noData={hasNoData}
|
|
346
356
|
tableName={config.visualizationType}
|
|
347
357
|
caption={caption}
|
|
348
358
|
stickyHeader
|
|
@@ -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
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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,7 +16,7 @@ const boxplotCellMatrix = ({ rows, config }): CellMatrix => {
|
|
|
16
16
|
columnThirdQuartile: labels.q3,
|
|
17
17
|
columnOutliers: labels.outliers,
|
|
18
18
|
values: labels.values,
|
|
19
|
-
|
|
19
|
+
columnCount: labels.count,
|
|
20
20
|
columnSd: 'Standard Deviation',
|
|
21
21
|
nonOutlierValues: 'Non Outliers',
|
|
22
22
|
columnLowerBounds: labels.lowerBounds,
|
|
@@ -28,30 +28,31 @@ const boxplotCellMatrix = ({ rows, config }): CellMatrix => {
|
|
|
28
28
|
return resolvedName
|
|
29
29
|
}
|
|
30
30
|
let resolveCell = (rowid, plot) => {
|
|
31
|
-
if (Number(rowid) === 0) return
|
|
32
|
-
if (Number(rowid) === 1) return plot.
|
|
33
|
-
if (Number(rowid) === 2) return plot.
|
|
34
|
-
if (Number(rowid) === 3) return plot.
|
|
35
|
-
if (Number(rowid) === 4) return plot.
|
|
36
|
-
if (Number(rowid) === 5) return plot.
|
|
37
|
-
if (Number(rowid) === 6) return plot.
|
|
38
|
-
if (Number(rowid) === 7) return plot.
|
|
39
|
-
if (Number(rowid) === 8) return plot.
|
|
40
|
-
if (Number(rowid) === 9) return plot.
|
|
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.columnOutliers.length > 0 ? plot.columnOutliers.toString() : '-'
|
|
40
|
+
if (Number(rowid) === 9) return plot.values.length > 0 ? plot.values.toString() : '-'
|
|
42
41
|
return <p>-</p>
|
|
43
42
|
}
|
|
44
43
|
// get list of data keys for each row
|
|
45
44
|
let dataKeys = rows.map(row => {
|
|
46
45
|
return row[0]
|
|
47
46
|
})
|
|
47
|
+
|
|
48
48
|
let columns = ['Measures', ...config.boxplot.categories]
|
|
49
49
|
dataKeys.shift() // remove index 0 // we did header column separately
|
|
50
|
+
|
|
50
51
|
return dataKeys.map((rowkey, index) => {
|
|
51
52
|
return columns.map((column, colnum) => {
|
|
52
53
|
let cellValue
|
|
53
54
|
if (column === 'Measures') {
|
|
54
|
-
let labelValue =
|
|
55
|
+
let labelValue = resolveName(rowkey)
|
|
55
56
|
cellValue = <>{labelValue}</>
|
|
56
57
|
} else {
|
|
57
58
|
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 '
|
|
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
|
|
@@ -32,7 +32,15 @@ export const getChartCellValue = (row: string, column: string, config: TableConf
|
|
|
32
32
|
let labelValue = rowObj[column] // just raw X axis string
|
|
33
33
|
if (column === config.xAxis?.dataKey) {
|
|
34
34
|
// not the prettiest, but helper functions work nicely here.
|
|
35
|
-
cellValue =
|
|
35
|
+
cellValue =
|
|
36
|
+
config.xAxis?.type === 'date'
|
|
37
|
+
? formatDate(
|
|
38
|
+
config.table?.dateDisplayFormat || config.xAxis?.dateDisplayFormat,
|
|
39
|
+
parseDate(config.xAxis?.dateParseFormat, labelValue)
|
|
40
|
+
)
|
|
41
|
+
: labelValue
|
|
42
|
+
cellValue =
|
|
43
|
+
config.xAxis?.type === 'continuous' ? formatNumber(runtimeData[row][column], 'bottom', false, config) : labelValue
|
|
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
|
|
59
|
+
cellValue = config.dataFormat
|
|
60
|
+
? formatNumber(runtimeData[row][column], resolvedAxis, false, config, addColParams)
|
|
61
|
+
: runtimeData[row][column]
|
|
52
62
|
} else {
|
|
53
|
-
cellValue = config.dataFormat
|
|
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 (
|
|
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 }> = ({
|
|
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
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
|
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
|
|
101
|
-
|
|
102
|
-
|
|
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
|
|
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
|
|
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'}
|
|
@@ -83,7 +83,7 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
83
83
|
</Tooltip>
|
|
84
84
|
}
|
|
85
85
|
/>
|
|
86
|
-
{config.type !== 'table'
|
|
86
|
+
{config.type !== 'table' ? (
|
|
87
87
|
<CheckBox
|
|
88
88
|
value={config.table.show}
|
|
89
89
|
fieldName='show'
|
|
@@ -108,6 +108,15 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
108
108
|
</Tooltip>
|
|
109
109
|
}
|
|
110
110
|
/>
|
|
111
|
+
) : (
|
|
112
|
+
<CheckBox
|
|
113
|
+
value={config.general?.showDownloadButton}
|
|
114
|
+
fieldName='showDownloadButton'
|
|
115
|
+
label='Show Download CSV link'
|
|
116
|
+
section='general'
|
|
117
|
+
updateField={updateField}
|
|
118
|
+
className='column-heading'
|
|
119
|
+
/>
|
|
111
120
|
)}
|
|
112
121
|
|
|
113
122
|
{config.visualizationType !== 'Box Plot' && config.type !== 'table' && (
|
|
@@ -249,15 +258,14 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
249
258
|
updateField={updateField}
|
|
250
259
|
/>
|
|
251
260
|
)}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
)}
|
|
261
|
+
|
|
262
|
+
<CheckBox
|
|
263
|
+
value={config.table.showDownloadLinkBelow}
|
|
264
|
+
fieldName='showDownloadLinkBelow'
|
|
265
|
+
label='Show Download Link Below Table'
|
|
266
|
+
section='table'
|
|
267
|
+
updateField={updateField}
|
|
268
|
+
/>
|
|
261
269
|
<label>
|
|
262
270
|
<span className='edit-label column-heading'>Table Cell Min Width</span>
|
|
263
271
|
<input
|
|
@@ -267,9 +275,17 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
267
275
|
/>
|
|
268
276
|
</label>
|
|
269
277
|
{config?.visualizationType !== 'Sankey' && (
|
|
270
|
-
<
|
|
271
|
-
|
|
272
|
-
|
|
278
|
+
<Select
|
|
279
|
+
value={config.table.groupBy}
|
|
280
|
+
fieldName={'groupBy'}
|
|
281
|
+
section='table'
|
|
282
|
+
label='Group By'
|
|
283
|
+
updateField={(_section, _subSection, _fieldName, value) => changeGroupBy(value)}
|
|
284
|
+
initial={PLACEHOLDER}
|
|
285
|
+
options={groupPivotColumns.filter(
|
|
286
|
+
col => col !== config.table.pivot?.columnName && !(config.table.pivot?.valueColumns || []).includes(col)
|
|
287
|
+
)}
|
|
288
|
+
tooltip={
|
|
273
289
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
274
290
|
<Tooltip.Target>
|
|
275
291
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
@@ -281,27 +297,11 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
281
297
|
</p>
|
|
282
298
|
</Tooltip.Content>
|
|
283
299
|
</Tooltip>
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
<select
|
|
287
|
-
value={config.table.groupBy}
|
|
288
|
-
onChange={event => {
|
|
289
|
-
changeGroupBy(event.target.value)
|
|
290
|
-
}}
|
|
291
|
-
>
|
|
292
|
-
{[
|
|
293
|
-
PLACEHOLDER,
|
|
294
|
-
...groupPivotColumns.filter(
|
|
295
|
-
col => col !== config.table.pivot?.columnName && col !== config.table.pivot?.valueColumn
|
|
296
|
-
)
|
|
297
|
-
].map(option => (
|
|
298
|
-
<option key={option}>{option}</option>
|
|
299
|
-
))}
|
|
300
|
-
</select>
|
|
301
|
-
</label>
|
|
300
|
+
}
|
|
301
|
+
/>
|
|
302
302
|
)}
|
|
303
303
|
<Select
|
|
304
|
-
label='Pivot Column
|
|
304
|
+
label='Pivot Column'
|
|
305
305
|
tooltip={
|
|
306
306
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
307
307
|
<Tooltip.Target>
|
|
@@ -314,7 +314,7 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
314
314
|
}
|
|
315
315
|
value={config.table.pivot?.columnName}
|
|
316
316
|
options={groupPivotColumns.filter(
|
|
317
|
-
col => col !== config.table.groupBy &&
|
|
317
|
+
col => col !== config.table.groupBy && !(config.table.pivot?.valueColumns || []).includes(col)
|
|
318
318
|
)}
|
|
319
319
|
initial='-Select-'
|
|
320
320
|
section='table'
|
|
@@ -21,7 +21,7 @@ const FieldSet: React.FC<FieldSetProps> = ({ fieldName, fieldKey, fieldType, con
|
|
|
21
21
|
if (!show)
|
|
22
22
|
return (
|
|
23
23
|
<div className='mb-1'>
|
|
24
|
-
<button onClick={() => setShow(fieldKey, true)}>
|
|
24
|
+
<button className='btn btn-light' onClick={() => setShow(fieldKey, true)}>
|
|
25
25
|
<Icon display='caretDown' />
|
|
26
26
|
</button>
|
|
27
27
|
<span> {fieldName ? `${fieldName}` : 'New ' + fieldType}</span>
|
|
@@ -30,7 +30,7 @@ const FieldSet: React.FC<FieldSetProps> = ({ fieldName, fieldKey, fieldType, con
|
|
|
30
30
|
return (
|
|
31
31
|
<fieldset className='edit-block mb-1' key={fieldKey}>
|
|
32
32
|
<div className='d-flex justify-content-between'>
|
|
33
|
-
<button onClick={() => setShow(fieldKey, false)}>
|
|
33
|
+
<button className='btn btn-light' onClick={() => setShow(fieldKey, false)}>
|
|
34
34
|
<Icon display='caretUp' />
|
|
35
35
|
</button>
|
|
36
36
|
<button
|