@cdc/core 4.24.9 → 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/LICENSE +201 -0
- package/assets/icon-combo-chart.svg +1 -0
- package/assets/icon-epi-chart.svg +27 -0
- package/components/AdvancedEditor/AdvancedEditor.tsx +17 -13
- package/components/Alert/components/Alert.tsx +34 -8
- package/components/BlurStrokeText.tsx +44 -0
- package/components/DataTable/DataTable.tsx +62 -36
- package/components/DataTable/DataTableStandAlone.tsx +37 -6
- package/components/DataTable/components/ChartHeader.tsx +31 -26
- package/components/DataTable/components/MapHeader.tsx +19 -10
- package/components/DataTable/components/SortIcon/index.tsx +25 -0
- package/components/DataTable/components/SortIcon/sort-icon.css +21 -0
- package/{styles/_data-table.scss → components/DataTable/data-table.css} +250 -298
- package/components/DataTable/helpers/boxplotCellMatrix.tsx +14 -13
- package/components/DataTable/helpers/customSort.ts +11 -15
- package/components/DataTable/helpers/getChartCellValue.ts +23 -5
- package/components/DataTable/helpers/getDataSeriesColumns.ts +5 -1
- package/components/DataTable/helpers/getNewSortBy.ts +35 -0
- package/components/DataTable/helpers/tests/customSort.test.ts +52 -0
- package/components/DataTable/helpers/tests/getNewSortBy.test.ts +26 -0
- package/components/EditorPanel/ColumnsEditor.tsx +81 -36
- package/components/EditorPanel/DataTableEditor.tsx +149 -43
- package/components/EditorPanel/FieldSetWrapper.tsx +2 -2
- package/components/EditorPanel/Inputs.tsx +68 -20
- package/components/EditorPanel/VizFilterEditor/NestedDropdownEditor.tsx +25 -7
- package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +30 -55
- package/components/{Filters.tsx → Filters/Filters.tsx} +60 -43
- package/components/Filters/helpers/applyQueuedActive.ts +12 -0
- package/components/Filters/helpers/getNestedOptions.ts +29 -0
- package/components/Filters/helpers/handleSorting.ts +18 -0
- package/components/Filters/helpers/tests/applyQueuedActive.test.ts +49 -0
- package/components/Filters/helpers/tests/getNestedOptions.test.ts +93 -0
- package/components/Filters/helpers/tests/handleSorting.test.ts +68 -0
- package/components/Filters/index.ts +5 -0
- package/components/Layout/components/Sidebar/components/sidebar.styles.scss +1 -7
- package/components/Layout/components/Visualization/visualizations.scss +1 -1
- package/components/Legend/Legend.Gradient.tsx +44 -36
- package/components/Loader/Loader.tsx +33 -0
- package/components/Loader/index.ts +1 -0
- package/components/Loader/loader.styles.css +13 -0
- package/components/MultiSelect/MultiSelect.tsx +85 -62
- package/components/MultiSelect/multiselect.styles.css +10 -7
- package/components/NestedDropdown/NestedDropdown.tsx +118 -56
- package/components/NestedDropdown/nestedDropdownHelpers.ts +34 -0
- package/components/NestedDropdown/nesteddropdown.styles.css +22 -13
- package/components/NestedDropdown/tests/nestedDropdownHelpers.test.ts +58 -0
- package/components/Table/Table.tsx +102 -34
- package/components/Table/components/GroupRow.tsx +1 -1
- package/components/_stories/BlurStrokeTest.stories.tsx +27 -0
- package/components/_stories/DataTable.stories.tsx +14 -0
- package/components/_stories/Filters.stories.tsx +57 -0
- package/components/_stories/NestedDropdown.stories.tsx +22 -46
- package/components/_stories/_mocks/DataTable/no-data.json +108 -0
- package/components/_stories/_mocks/nested-dropdown.json +30 -0
- package/components/_stories/styles.scss +0 -1
- package/components/ui/Icon.tsx +19 -6
- package/components/ui/{Tooltip.jsx → Tooltip.tsx} +38 -14
- package/data/colorPalettes.js +107 -10
- package/dist/cove-main.css +6080 -0
- package/dist/cove-main.css.map +1 -0
- package/helpers/DataTransform.ts +2 -1
- package/helpers/addValuesToFilters.ts +8 -3
- package/helpers/cove/{number.js → number.ts} +62 -27
- package/helpers/coveUpdateWorker.ts +6 -7
- package/helpers/fetchRemoteData.js +32 -37
- package/helpers/formatConfigBeforeSave.ts +17 -1
- package/helpers/gatherQueryParams.ts +12 -2
- package/helpers/pivotData.ts +52 -11
- package/helpers/queryStringUtils.ts +6 -0
- package/helpers/tests/gatherQueryParams.test.ts +34 -0
- package/helpers/tests/pivotData.test.ts +50 -0
- package/helpers/useDataVizClasses.ts +42 -20
- package/helpers/ver/4.24.10.ts +47 -0
- package/helpers/ver/4.24.9.ts +0 -3
- package/helpers/ver/tests/4.24.10.test.ts +45 -0
- package/helpers/viewports.ts +9 -0
- package/package.json +7 -3
- package/styles/_button-section.scss +5 -1
- package/styles/_global-variables.scss +20 -2
- package/styles/_global.scss +22 -30
- package/styles/_reset.scss +2 -26
- package/styles/base.scss +0 -1
- package/styles/cove-main.scss +6 -0
- package/styles/filters.scss +6 -26
- 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/styles/v2/components/ui/tooltip.scss +42 -40
- package/styles/v2/layout/_component.scss +0 -6
- package/styles/v2/layout/index.scss +0 -1
- package/types/Axis.ts +4 -0
- package/types/BoxPlot.ts +5 -3
- package/types/Color.ts +1 -1
- package/types/General.ts +1 -0
- 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 +3 -2
- package/types/Visualization.ts +19 -8
- package/types/VizFilter.ts +2 -1
- package/components/DataTable/components/Icons.tsx +0 -10
- package/components/_stories/EditorPanel.stories.tsx +0 -54
- package/components/_stories/Layout.Debug.stories.tsx +0 -91
- package/components/ui/Select.jsx +0 -30
- package/helpers/getGradientLegendWidth.ts +0 -15
|
@@ -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 : ''
|
|
@@ -56,6 +56,10 @@ export const getDataSeriesColumns = (config: TableConfig, isVertical: boolean, r
|
|
|
56
56
|
}
|
|
57
57
|
})
|
|
58
58
|
|
|
59
|
-
tmpSeriesColumns.sort((a, b) =>
|
|
59
|
+
tmpSeriesColumns.sort((a, b) => {
|
|
60
|
+
if (a === 'pivotColumn') return -1
|
|
61
|
+
if (b === 'pivotColumn') return 1
|
|
62
|
+
return columnOrderingHash[a] - columnOrderingHash[b]
|
|
63
|
+
})
|
|
60
64
|
return tmpSeriesColumns
|
|
61
65
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
type SortBy = {
|
|
2
|
+
asc: boolean
|
|
3
|
+
column?: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export const getNewSortBy = (
|
|
7
|
+
sortBy: SortBy,
|
|
8
|
+
column: string,
|
|
9
|
+
index: number
|
|
10
|
+
): { column: string; asc: boolean; colIndex: number } => {
|
|
11
|
+
let asc
|
|
12
|
+
let sortByCol = column
|
|
13
|
+
const ascending = sortBy.asc === true
|
|
14
|
+
const descending = sortBy.asc === false
|
|
15
|
+
const isInactive = sortBy.asc === undefined
|
|
16
|
+
const noColumnSelected = sortBy.column === undefined
|
|
17
|
+
if (noColumnSelected || sortBy.column !== column) {
|
|
18
|
+
// this is the first time a column is clicked
|
|
19
|
+
asc = true
|
|
20
|
+
} else {
|
|
21
|
+
// clicking the same column
|
|
22
|
+
if (descending) {
|
|
23
|
+
// reset
|
|
24
|
+
sortByCol = undefined
|
|
25
|
+
asc = undefined
|
|
26
|
+
}
|
|
27
|
+
if (isInactive) {
|
|
28
|
+
asc = true
|
|
29
|
+
}
|
|
30
|
+
if (ascending) {
|
|
31
|
+
asc = false
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return { column: sortByCol, asc, colIndex: index }
|
|
35
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { customSort } from '../customSort'
|
|
3
|
+
|
|
4
|
+
describe('customSort()', () => {
|
|
5
|
+
it('should return positive number when a > b', () => {
|
|
6
|
+
const a = 3
|
|
7
|
+
const b = 1
|
|
8
|
+
const sortBy = { column: 'someColumn', asc: true, colIndex: 0 }
|
|
9
|
+
const config = { type: 'map' }
|
|
10
|
+
expect(customSort(a, b, sortBy, config)).greaterThan(0)
|
|
11
|
+
expect(customSort(a, b, sortBy, { type: 'notMap' })).greaterThan(0)
|
|
12
|
+
})
|
|
13
|
+
it('should return negative number when a < b', () => {
|
|
14
|
+
const a = 1
|
|
15
|
+
const b = 3
|
|
16
|
+
const sortBy = { column: 'someColumn', asc: true, colIndex: 0 }
|
|
17
|
+
const config = { type: 'map' }
|
|
18
|
+
expect(customSort(a, b, sortBy, config)).lessThan(0)
|
|
19
|
+
expect(customSort(a, b, sortBy, { type: 'notMap' })).lessThan(0)
|
|
20
|
+
})
|
|
21
|
+
it('works for dates', () => {
|
|
22
|
+
const a = 2000
|
|
23
|
+
const b = 1999
|
|
24
|
+
const sortBy = { column: 'someColumn', asc: true, colIndex: 0 }
|
|
25
|
+
expect(
|
|
26
|
+
customSort(a, b, sortBy, { xAxis: { dataKey: sortBy.column, dateParseFormat: '%Y', type: 'date' } })
|
|
27
|
+
).greaterThan(0)
|
|
28
|
+
expect(
|
|
29
|
+
customSort(b, a, sortBy, { xAxis: { dataKey: sortBy.column, dateParseFormat: '%Y', type: 'date' } })
|
|
30
|
+
).lessThan(0)
|
|
31
|
+
})
|
|
32
|
+
it('works for strings', () => {
|
|
33
|
+
const a = 'banana'
|
|
34
|
+
const b = 'apple'
|
|
35
|
+
const sortBy = { column: 'someColumn', asc: true, colIndex: 0 }
|
|
36
|
+
const config = { type: 'map' }
|
|
37
|
+
expect(customSort(a, b, sortBy, config)).greaterThan(0)
|
|
38
|
+
expect(customSort(a, b, sortBy, { type: 'notMap' })).greaterThan(0)
|
|
39
|
+
expect(customSort(b, a, sortBy, config)).lessThan(0)
|
|
40
|
+
expect(customSort(b, a, sortBy, { type: 'notMap' })).lessThan(0)
|
|
41
|
+
})
|
|
42
|
+
it('works for strings after number', () => {
|
|
43
|
+
const a = 'banana'
|
|
44
|
+
const b = '1'
|
|
45
|
+
const sortBy = { column: 'someColumn', asc: true, colIndex: 0 }
|
|
46
|
+
const config = { type: 'map' }
|
|
47
|
+
expect(customSort(a, b, sortBy, config)).greaterThan(0)
|
|
48
|
+
expect(customSort(a, b, sortBy, { type: 'notMap' })).greaterThan(0)
|
|
49
|
+
expect(customSort(b, a, sortBy, config)).lessThan(0)
|
|
50
|
+
expect(customSort(b, a, sortBy, { type: 'notMap' })).lessThan(0)
|
|
51
|
+
})
|
|
52
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { getNewSortBy } from '../getNewSortBy'
|
|
3
|
+
|
|
4
|
+
describe('getNewSortBy()', () => {
|
|
5
|
+
it('should return ascending when currently undefined', () => {
|
|
6
|
+
const sortBy = { column: undefined, asc: undefined, colIndex: 0 }
|
|
7
|
+
const column = 'someColumn'
|
|
8
|
+
const index = 1
|
|
9
|
+
const result = getNewSortBy(sortBy, column, index)
|
|
10
|
+
expect(result).toEqual({ column, asc: true, colIndex: index })
|
|
11
|
+
})
|
|
12
|
+
it('should return ascending false when currently true', () => {
|
|
13
|
+
const sortBy = { column: 'someColumn', asc: true, colIndex: 0 }
|
|
14
|
+
const column = 'someColumn'
|
|
15
|
+
const index = 1
|
|
16
|
+
const result = getNewSortBy(sortBy, column, index)
|
|
17
|
+
expect(result).toEqual({ column, asc: false, colIndex: index })
|
|
18
|
+
})
|
|
19
|
+
it('should return ascending undefined when currently false', () => {
|
|
20
|
+
const sortBy = { column: 'someColumn', asc: false, colIndex: 0 }
|
|
21
|
+
const column = 'someColumn'
|
|
22
|
+
const index = 1
|
|
23
|
+
const result = getNewSortBy(sortBy, column, index)
|
|
24
|
+
expect(result).toEqual({ column: undefined, asc: undefined, colIndex: index })
|
|
25
|
+
})
|
|
26
|
+
})
|
|
@@ -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'}
|
|
@@ -41,6 +41,7 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
41
41
|
|
|
42
42
|
const excludeColumns = (section, subSection, fieldName, excludedColNames: string[]) => {
|
|
43
43
|
const newColumns = _.cloneDeep(config.columns)
|
|
44
|
+
|
|
44
45
|
const colNames: string[] = []
|
|
45
46
|
for (let colKey in newColumns) {
|
|
46
47
|
const col = newColumns[colKey]
|
|
@@ -48,6 +49,8 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
48
49
|
if (excludedColNames.includes(col.name)) {
|
|
49
50
|
// ensure all excluded columns are set to false
|
|
50
51
|
newColumns[colKey].dataTable = false
|
|
52
|
+
} else {
|
|
53
|
+
newColumns[colKey].dataTable = true
|
|
51
54
|
}
|
|
52
55
|
}
|
|
53
56
|
excludedColNames.forEach(colName => {
|
|
@@ -80,7 +83,7 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
80
83
|
</Tooltip>
|
|
81
84
|
}
|
|
82
85
|
/>
|
|
83
|
-
{config.type !== 'table'
|
|
86
|
+
{config.type !== 'table' ? (
|
|
84
87
|
<CheckBox
|
|
85
88
|
value={config.table.show}
|
|
86
89
|
fieldName='show'
|
|
@@ -91,14 +94,29 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
91
94
|
tooltip={
|
|
92
95
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
93
96
|
<Tooltip.Target>
|
|
94
|
-
<Icon
|
|
97
|
+
<Icon
|
|
98
|
+
display='question'
|
|
99
|
+
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
100
|
+
/>
|
|
95
101
|
</Tooltip.Target>
|
|
96
102
|
<Tooltip.Content>
|
|
97
|
-
<p>
|
|
103
|
+
<p>
|
|
104
|
+
Hiding the data table may affect accessibility. An alternate form of accessing visualization data is a
|
|
105
|
+
508 requirement.
|
|
106
|
+
</p>
|
|
98
107
|
</Tooltip.Content>
|
|
99
108
|
</Tooltip>
|
|
100
109
|
}
|
|
101
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
|
+
/>
|
|
102
120
|
)}
|
|
103
121
|
|
|
104
122
|
{config.visualizationType !== 'Box Plot' && config.type !== 'table' && (
|
|
@@ -112,7 +130,10 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
112
130
|
tooltip={
|
|
113
131
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
114
132
|
<Tooltip.Target>
|
|
115
|
-
<Icon
|
|
133
|
+
<Icon
|
|
134
|
+
display='question'
|
|
135
|
+
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
136
|
+
/>
|
|
116
137
|
</Tooltip.Target>
|
|
117
138
|
<Tooltip.Content>
|
|
118
139
|
<p>This will draw the data table with vertical data instead of horizontal.</p>
|
|
@@ -135,7 +156,10 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
135
156
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
136
157
|
</Tooltip.Target>
|
|
137
158
|
<Tooltip.Content>
|
|
138
|
-
<p>
|
|
159
|
+
<p>
|
|
160
|
+
To comply with 508 standards, if the first column in the data table has no header, enter a brief one
|
|
161
|
+
here.
|
|
162
|
+
</p>
|
|
139
163
|
</Tooltip.Content>
|
|
140
164
|
</Tooltip>
|
|
141
165
|
}
|
|
@@ -160,46 +184,124 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
160
184
|
</Tooltip>
|
|
161
185
|
}
|
|
162
186
|
/>
|
|
163
|
-
<CheckBox
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
{config.
|
|
187
|
+
<CheckBox
|
|
188
|
+
value={config.table.limitHeight}
|
|
189
|
+
section='table'
|
|
190
|
+
fieldName='limitHeight'
|
|
191
|
+
label=' Limit Table Height'
|
|
192
|
+
updateField={updateField}
|
|
193
|
+
/>
|
|
194
|
+
{config.table.limitHeight && (
|
|
195
|
+
<TextField
|
|
196
|
+
value={config.table.height}
|
|
197
|
+
section='table'
|
|
198
|
+
fieldName='height'
|
|
199
|
+
label='Data Table Height'
|
|
200
|
+
type='number'
|
|
201
|
+
min={0}
|
|
202
|
+
max={500}
|
|
203
|
+
placeholder='Height(px)'
|
|
204
|
+
updateField={updateField}
|
|
205
|
+
/>
|
|
206
|
+
)}
|
|
207
|
+
{config?.visualizationType !== 'Sankey' && (
|
|
208
|
+
<MultiSelect
|
|
209
|
+
key={excludedColumns.join('') + 'excluded'}
|
|
210
|
+
options={dataColumns.map(c => ({ label: c, value: c }))}
|
|
211
|
+
selected={excludedColumns}
|
|
212
|
+
fieldName='dataTable'
|
|
213
|
+
label='Exclude Columns'
|
|
214
|
+
section='columns'
|
|
215
|
+
updateField={excludeColumns}
|
|
216
|
+
/>
|
|
217
|
+
)}
|
|
218
|
+
<CheckBox
|
|
219
|
+
value={config.table.collapsible}
|
|
220
|
+
fieldName='collapsible'
|
|
221
|
+
label=' Collapsible'
|
|
222
|
+
section='table'
|
|
223
|
+
updateField={updateField}
|
|
224
|
+
/>
|
|
225
|
+
{config.table.collapsible !== false && (
|
|
226
|
+
<CheckBox
|
|
227
|
+
value={config.table.expanded}
|
|
228
|
+
fieldName='expanded'
|
|
229
|
+
label=' Expanded by Default'
|
|
230
|
+
section='table'
|
|
231
|
+
updateField={updateField}
|
|
232
|
+
/>
|
|
233
|
+
)}
|
|
234
|
+
{isDashboard && config.type !== 'table' && (
|
|
235
|
+
<CheckBox
|
|
236
|
+
value={config.table.showDataTableLink}
|
|
237
|
+
fieldName='showDataTableLink'
|
|
238
|
+
label='Show Data Table Name & Link'
|
|
239
|
+
section='table'
|
|
240
|
+
updateField={updateField}
|
|
241
|
+
/>
|
|
242
|
+
)}
|
|
243
|
+
{isLoadedFromUrl && (
|
|
244
|
+
<CheckBox
|
|
245
|
+
value={config.table.showDownloadUrl}
|
|
246
|
+
fieldName='showDownloadUrl'
|
|
247
|
+
label='Show URL to Automatically Updated Data'
|
|
248
|
+
section='table'
|
|
249
|
+
updateField={updateField}
|
|
250
|
+
/>
|
|
251
|
+
)}
|
|
252
|
+
{config.type !== 'table' && (
|
|
253
|
+
<CheckBox
|
|
254
|
+
value={config.table.showDownloadImgButton}
|
|
255
|
+
fieldName='showDownloadImgButton'
|
|
256
|
+
label='Display Image Button'
|
|
257
|
+
section='table'
|
|
258
|
+
updateField={updateField}
|
|
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
|
+
/>
|
|
171
269
|
<label>
|
|
172
270
|
<span className='edit-label column-heading'>Table Cell Min Width</span>
|
|
173
|
-
<input
|
|
271
|
+
<input
|
|
272
|
+
type='number'
|
|
273
|
+
value={config.table.cellMinWidth ? config.table.cellMinWidth : 0}
|
|
274
|
+
onChange={e => updateField('table', null, 'cellMinWidth', e.target.value)}
|
|
275
|
+
/>
|
|
174
276
|
</label>
|
|
175
277
|
{config?.visualizationType !== 'Sankey' && (
|
|
176
|
-
<
|
|
177
|
-
|
|
178
|
-
|
|
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={
|
|
179
289
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
180
290
|
<Tooltip.Target>
|
|
181
291
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
182
292
|
</Tooltip.Target>
|
|
183
293
|
<Tooltip.Content>
|
|
184
|
-
<p>
|
|
294
|
+
<p>
|
|
295
|
+
Choose a column to use for grouping data rows. The selected column will not be shown in the data
|
|
296
|
+
table. You will only be able to choose a column which does not have a column configuration.
|
|
297
|
+
</p>
|
|
185
298
|
</Tooltip.Content>
|
|
186
299
|
</Tooltip>
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
<select
|
|
190
|
-
value={config.table.groupBy}
|
|
191
|
-
onChange={event => {
|
|
192
|
-
changeGroupBy(event.target.value)
|
|
193
|
-
}}
|
|
194
|
-
>
|
|
195
|
-
{[PLACEHOLDER, ...groupPivotColumns.filter(col => col !== config.table.pivot?.columnName && col !== config.table.pivot?.valueColumn)].map(option => (
|
|
196
|
-
<option key={option}>{option}</option>
|
|
197
|
-
))}
|
|
198
|
-
</select>
|
|
199
|
-
</label>
|
|
300
|
+
}
|
|
301
|
+
/>
|
|
200
302
|
)}
|
|
201
303
|
<Select
|
|
202
|
-
label='Pivot Column
|
|
304
|
+
label='Pivot Column'
|
|
203
305
|
tooltip={
|
|
204
306
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
205
307
|
<Tooltip.Target>
|
|
@@ -211,7 +313,9 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
211
313
|
</Tooltip>
|
|
212
314
|
}
|
|
213
315
|
value={config.table.pivot?.columnName}
|
|
214
|
-
options={groupPivotColumns.filter(
|
|
316
|
+
options={groupPivotColumns.filter(
|
|
317
|
+
col => col !== config.table.groupBy && !(config.table.pivot?.valueColumns || []).includes(col)
|
|
318
|
+
)}
|
|
215
319
|
initial='-Select-'
|
|
216
320
|
section='table'
|
|
217
321
|
subsection='pivot'
|
|
@@ -219,25 +323,27 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
219
323
|
updateField={updateField}
|
|
220
324
|
/>
|
|
221
325
|
{config.table.pivot?.columnName && (
|
|
222
|
-
<
|
|
223
|
-
|
|
326
|
+
<MultiSelect
|
|
327
|
+
key={config.table.pivot?.columnName}
|
|
328
|
+
options={groupPivotColumns
|
|
329
|
+
.filter(col => col !== config.table.pivot?.columnName && col !== config.table.groupBy)
|
|
330
|
+
.map(c => ({ label: c, value: c }))}
|
|
331
|
+
selected={config.table.pivot?.valueColumns}
|
|
332
|
+
label='Pivot Value Column(s) '
|
|
333
|
+
section='table'
|
|
334
|
+
subsection='pivot'
|
|
335
|
+
fieldName='valueColumns'
|
|
336
|
+
updateField={updateField}
|
|
224
337
|
tooltip={
|
|
225
338
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
226
339
|
<Tooltip.Target>
|
|
227
340
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
228
341
|
</Tooltip.Target>
|
|
229
342
|
<Tooltip.Content>
|
|
230
|
-
<p>The column whos values will be pivoted under the column selected as the Filter.</p>
|
|
343
|
+
<p>The column(s) whos values will be pivoted under the column selected as the Filter.</p>
|
|
231
344
|
</Tooltip.Content>
|
|
232
345
|
</Tooltip>
|
|
233
346
|
}
|
|
234
|
-
value={config.table.pivot?.valueColumn}
|
|
235
|
-
initial='-Select-'
|
|
236
|
-
section='table'
|
|
237
|
-
options={groupPivotColumns.filter(col => col !== config.table.pivot?.columnName && col !== config.table.groupBy)}
|
|
238
|
-
subsection='pivot'
|
|
239
|
-
fieldName='valueColumn'
|
|
240
|
-
updateField={updateField}
|
|
241
347
|
/>
|
|
242
348
|
)}
|
|
243
349
|
</>
|
|
@@ -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
|