@cdc/core 4.25.3 → 4.25.6-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.
- package/assets/icon-close.svg +1 -1
- package/components/Alert/components/Alert.tsx +1 -1
- package/components/DataTable/DataTable.tsx +18 -16
- package/components/DataTable/DataTableStandAlone.tsx +15 -9
- package/components/DataTable/components/CellAnchor.tsx +1 -1
- package/components/DataTable/components/ChartHeader.tsx +8 -5
- package/components/DataTable/components/DataTableEditorPanel.tsx +25 -3
- package/components/DataTable/components/MapHeader.tsx +1 -0
- package/components/DataTable/helpers/chartCellMatrix.tsx +14 -10
- package/components/DataTable/helpers/getChartCellValue.ts +42 -26
- package/components/DataTable/helpers/mapCellMatrix.tsx +25 -7
- package/components/DownloadButton.tsx +17 -2
- package/components/EditorPanel/DataTableEditor.tsx +1 -1
- package/components/EditorPanel/FootnotesEditor.tsx +76 -22
- package/components/EditorPanel/Inputs.tsx +12 -4
- package/components/EditorPanel/VizFilterEditor/NestedDropdownEditor.tsx +3 -2
- package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +51 -35
- package/components/Filters/Filters.tsx +158 -461
- package/components/Filters/components/Dropdown.tsx +39 -0
- package/components/Filters/components/Tabs.tsx +82 -0
- package/components/Filters/helpers/getChangedFilters.ts +31 -0
- package/components/Filters/helpers/getNestedOptions.ts +2 -2
- package/components/Filters/helpers/handleSorting.ts +2 -2
- package/components/Filters/helpers/tests/getChangedFilters.test.ts +92 -0
- package/components/Filters/helpers/tests/getNestedOptions.test.ts +31 -0
- package/components/Filters/index.ts +1 -1
- package/components/Footnotes/Footnotes.tsx +1 -1
- package/components/Footnotes/FootnotesStandAlone.tsx +8 -33
- package/components/Layout/components/Visualization/index.tsx +4 -3
- package/components/Legend/Legend.Gradient.tsx +68 -24
- package/components/MultiSelect/MultiSelect.tsx +3 -6
- package/components/MultiSelect/multiselect.styles.css +2 -0
- package/components/NestedDropdown/NestedDropdown.tsx +21 -21
- package/components/RichTooltip/RichTooltip.tsx +37 -0
- package/components/RichTooltip/richTooltip.css +16 -0
- package/components/Table/Table.tsx +142 -142
- package/components/Table/components/Row.tsx +1 -1
- package/components/Table/table.styles.css +10 -0
- package/components/_stories/DataTable.stories.tsx +9 -2
- package/components/_stories/Table.stories.tsx +1 -1
- package/components/_stories/styles.scss +0 -4
- package/components/ui/Accordion.jsx +8 -1
- package/components/ui/Title/index.tsx +4 -1
- package/components/ui/Title/{Title.scss → title.styles.css} +0 -2
- package/components/ui/_stories/Colors.stories.mdx +220 -0
- package/components/ui/_stories/IconGallery.stories.mdx +14 -0
- package/components/ui/_stories/Title.stories.tsx +29 -4
- package/components/ui/accordion.styles.css +3 -0
- package/data/colorPalettes.js +0 -1
- package/dist/cove-main.css +3 -8
- package/dist/cove-main.css.map +1 -1
- package/helpers/constants.ts +6 -0
- package/helpers/cove/accessibility.ts +7 -8
- package/helpers/cove/number.ts +5 -3
- package/helpers/coveUpdateWorker.ts +9 -1
- package/helpers/filterOrderOptions.ts +17 -0
- package/helpers/formatConfigBeforeSave.ts +19 -32
- package/helpers/isNumber.ts +20 -0
- package/helpers/isRightAlignedTableValue.js +1 -1
- package/helpers/pivotData.ts +16 -11
- package/helpers/tests/pivotData.test.ts +74 -0
- package/helpers/updateFieldFactory.ts +1 -0
- package/helpers/ver/4.25.3.ts +25 -2
- package/helpers/ver/4.25.4.ts +110 -0
- package/helpers/ver/4.25.6.ts +36 -0
- package/helpers/ver/4.25.7.ts +26 -0
- package/helpers/ver/tests/4.25.4.test.ts +89 -0
- package/helpers/ver/tests/4.25.6.test.ts +84 -0
- package/helpers/viewports.ts +4 -0
- package/package.json +7 -6
- package/styles/_global-variables.scss +3 -0
- package/styles/_global.scss +0 -4
- package/styles/_reset.scss +0 -6
- package/styles/filters.scss +0 -4
- package/styles/v2/main.scss +0 -5
- package/types/Axis.ts +2 -0
- package/types/DataSet.ts +14 -0
- package/types/Footnotes.ts +5 -2
- package/types/General.ts +1 -0
- package/types/Legend.ts +1 -0
- package/types/Table.ts +1 -0
- package/types/Visualization.ts +3 -12
- package/types/VizFilter.ts +3 -0
- package/components/ui/_stories/Colors.stories.tsx +0 -92
- package/components/ui/_stories/Icon.stories.tsx +0 -29
- package/helpers/cove/fontSettings.ts +0 -2
- package/helpers/isNumber.js +0 -24
- package/helpers/isNumberLog.js +0 -18
- /package/helpers/{fetchRemoteData.js → fetchRemoteData.ts} +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether the given input is a valid number.
|
|
3
|
+
*
|
|
4
|
+
* Handles both numeric types and numeric strings, including negative values.
|
|
5
|
+
*
|
|
6
|
+
* @param value - The value to check. Can be of any type.
|
|
7
|
+
* @returns boolean - True if the value is a number or a numeric string.
|
|
8
|
+
*/
|
|
9
|
+
export default function isNumber(value: unknown = ''): boolean {
|
|
10
|
+
if (typeof value === 'number') {
|
|
11
|
+
return !Number.isNaN(value)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (typeof value === 'string') {
|
|
15
|
+
return value.trim() !== '' && /^-?\d+(\.\d+)?$/.test(value.trim())
|
|
16
|
+
// Matches optional leading "-", integers, or decimals (e.g., "-123", "123.45")
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return false
|
|
20
|
+
}
|
|
@@ -12,7 +12,7 @@ export default function isRightAlignedTableValue(value = '') {
|
|
|
12
12
|
if (/^\d{4}-\d{1,2}-\d{1,2}$/.test(value)) {
|
|
13
13
|
return false
|
|
14
14
|
}
|
|
15
|
-
return numericStrings.includes(value) || /^[\$\d\.\%\,\-\s\(\)CI]*$/.test(value)
|
|
15
|
+
return numericStrings.includes(value) || /^[\$\d\.\%\,\-\s\(\)CI<>]*$/.test(value)
|
|
16
16
|
}
|
|
17
17
|
return false
|
|
18
18
|
}
|
package/helpers/pivotData.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import _ from 'lodash'
|
|
2
2
|
|
|
3
|
-
const getKeyFromRow = (row: Record<string, any>, columns: string[]) => {
|
|
4
|
-
return columns.map(column => row[column] || '').join(':')
|
|
5
|
-
}
|
|
6
|
-
|
|
7
3
|
const getColumns = (data: Record<string, any>[], columnName: string, pivot: string[], excludeColumns: string[]) => {
|
|
8
4
|
const excludedColumns = [columnName, ...pivot, ...excludeColumns]
|
|
9
5
|
return _.uniq(data.flatMap(row => Object.keys(row))).filter(col => !excludedColumns.includes(col))
|
|
@@ -18,18 +14,29 @@ export const pivotData = (
|
|
|
18
14
|
excludeColumns: string[]
|
|
19
15
|
): Record<string, any>[] => {
|
|
20
16
|
const columns = getColumns(data, columnName, pivot, excludeColumns)
|
|
21
|
-
const newColumns = {
|
|
17
|
+
const newColumns = data.reduce((acc, row) => {
|
|
18
|
+
acc[row[columnName]] = ''
|
|
19
|
+
return acc
|
|
20
|
+
}, {})
|
|
21
|
+
|
|
22
|
+
const getKeyFromRow = (row: Record<string, any>, columns: string[], index) => {
|
|
23
|
+
// if there is only one column header, we need to avoid duplicate values overwriting each other other values in the row
|
|
24
|
+
const isSingleColumn = Object.keys(newColumns).length === 1
|
|
25
|
+
const keyIndex = isSingleColumn ? index : ''
|
|
26
|
+
return columns.map(column => row[column] || '').join(':') + keyIndex
|
|
27
|
+
}
|
|
28
|
+
|
|
22
29
|
// there should be one row for every aggregate row
|
|
23
|
-
const aggregateRows = data.reduce((acc, row) => {
|
|
24
|
-
const key = getKeyFromRow(row, columns)
|
|
30
|
+
const aggregateRows = data.reduce((acc, row, index) => {
|
|
31
|
+
const key = getKeyFromRow(row, columns, index)
|
|
25
32
|
if (!acc[key]) {
|
|
26
33
|
acc[key] = {}
|
|
27
34
|
}
|
|
28
35
|
return acc
|
|
29
36
|
}, {})
|
|
30
37
|
|
|
31
|
-
data.forEach(row => {
|
|
32
|
-
const key = getKeyFromRow(row, columns)
|
|
38
|
+
data.forEach((row, index) => {
|
|
39
|
+
const key = getKeyFromRow(row, columns, index)
|
|
33
40
|
if (pivot.length > 1) {
|
|
34
41
|
pivot.forEach(pivotColumn => {
|
|
35
42
|
const toAdd = _.omit(row, [columnName, ...pivot])
|
|
@@ -50,8 +57,6 @@ export const pivotData = (
|
|
|
50
57
|
_pivotedFrom: _pivot
|
|
51
58
|
}
|
|
52
59
|
}
|
|
53
|
-
|
|
54
|
-
newColumns[row[columnName]] = ''
|
|
55
60
|
})
|
|
56
61
|
|
|
57
62
|
if (pivot.length > 1) {
|
|
@@ -51,4 +51,78 @@ describe('pivotData', () => {
|
|
|
51
51
|
{ city: 'San Francisco', Jane: 'yellow', John: 'green', _pivotedFrom: 'color' }
|
|
52
52
|
])
|
|
53
53
|
})
|
|
54
|
+
it('should allow for duplicate data when there is 1 Column Header but different columnName data', () => {
|
|
55
|
+
// when there are multiple pivot value columns, if any other data is present it will break the pivot.
|
|
56
|
+
// so we need to tell it which columns to exclude from the pivot.
|
|
57
|
+
// 'other' is added here as an example.
|
|
58
|
+
const data = [
|
|
59
|
+
{ name: 'John', age: 27, color: 'blue', city: 'New York', other: 'yes' },
|
|
60
|
+
{ name: 'Jane', age: 27, color: 'red', city: 'New York', other: 'no' },
|
|
61
|
+
{ name: 'Bob', age: 31, color: 'yellow', city: 'New York', other: 'yes' },
|
|
62
|
+
{ name: 'Betty', age: 31, color: 'green', city: 'New York', other: 'no' },
|
|
63
|
+
{ name: 'Jane', age: 31, color: 'yellow', city: 'New York', other: 'yes' },
|
|
64
|
+
{ name: 'John', age: 31, color: 'green', city: 'New York', other: 'no' },
|
|
65
|
+
{ name: 'Bob', age: 27, color: 'blue', city: 'New York', other: 'yes' },
|
|
66
|
+
{ name: 'Betty', age: 27, color: 'red', city: 'New York', other: 'no' }
|
|
67
|
+
]
|
|
68
|
+
const result = pivotData(data, 'city', ['name'], [])
|
|
69
|
+
expect(result).toEqual([
|
|
70
|
+
{
|
|
71
|
+
'New York': 'John',
|
|
72
|
+
age: 27,
|
|
73
|
+
color: 'blue',
|
|
74
|
+
other: 'yes',
|
|
75
|
+
_pivotedFrom: 'name'
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
'New York': 'Jane',
|
|
79
|
+
age: 27,
|
|
80
|
+
color: 'red',
|
|
81
|
+
other: 'no',
|
|
82
|
+
_pivotedFrom: 'name'
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
'New York': 'Bob',
|
|
86
|
+
age: 31,
|
|
87
|
+
color: 'yellow',
|
|
88
|
+
other: 'yes',
|
|
89
|
+
_pivotedFrom: 'name'
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
'New York': 'Betty',
|
|
93
|
+
age: 31,
|
|
94
|
+
color: 'green',
|
|
95
|
+
other: 'no',
|
|
96
|
+
_pivotedFrom: 'name'
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
'New York': 'Jane',
|
|
100
|
+
age: 31,
|
|
101
|
+
color: 'yellow',
|
|
102
|
+
other: 'yes',
|
|
103
|
+
_pivotedFrom: 'name'
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
'New York': 'John',
|
|
107
|
+
age: 31,
|
|
108
|
+
color: 'green',
|
|
109
|
+
other: 'no',
|
|
110
|
+
_pivotedFrom: 'name'
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
'New York': 'Bob',
|
|
114
|
+
age: 27,
|
|
115
|
+
color: 'blue',
|
|
116
|
+
other: 'yes',
|
|
117
|
+
_pivotedFrom: 'name'
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
'New York': 'Betty',
|
|
121
|
+
age: 27,
|
|
122
|
+
color: 'red',
|
|
123
|
+
other: 'no',
|
|
124
|
+
_pivotedFrom: 'name'
|
|
125
|
+
}
|
|
126
|
+
])
|
|
127
|
+
})
|
|
54
128
|
})
|
|
@@ -18,6 +18,7 @@ export const updateFieldFactory =
|
|
|
18
18
|
const isArray = Array.isArray(config[section])
|
|
19
19
|
|
|
20
20
|
let sectionValue = isArray ? [...config[section], newValue] : { ...config[section], [fieldName]: newValue }
|
|
21
|
+
if (!fieldName && !legacy) sectionValue = newValue
|
|
21
22
|
|
|
22
23
|
if (null !== subsection) {
|
|
23
24
|
if (isArray) {
|
package/helpers/ver/4.25.3.ts
CHANGED
|
@@ -2,17 +2,40 @@ import _ from 'lodash'
|
|
|
2
2
|
|
|
3
3
|
const remapTableDownloadCSV = config => {
|
|
4
4
|
if (config.general?.showDownloadButton !== undefined) {
|
|
5
|
-
|
|
5
|
+
let download = config.general.showDownloadButton
|
|
6
|
+
if (config.type === 'chart') {
|
|
7
|
+
download = config.table.download || config.general.showDownloadButton
|
|
8
|
+
}
|
|
6
9
|
delete config.general.showDownloadButton
|
|
7
10
|
config.table.download = download
|
|
8
11
|
}
|
|
9
12
|
return config
|
|
10
13
|
}
|
|
11
14
|
|
|
15
|
+
const handleVisualizations = newConfig => {
|
|
16
|
+
if (newConfig.type === 'dashboard') {
|
|
17
|
+
Object.keys(newConfig.visualizations).forEach(key => {
|
|
18
|
+
const currentViz = newConfig.visualizations[key]
|
|
19
|
+
remapTableDownloadCSV(currentViz)
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
remapTableDownloadCSV(newConfig)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const migrateAreaChart = config => {
|
|
26
|
+
// Migrate regular Area Chart to Stacked
|
|
27
|
+
if (config.visualizationType === 'Area Chart' && config.visualizationSubType === 'regular') {
|
|
28
|
+
config.visualizationSubType = 'stacked'
|
|
29
|
+
}
|
|
30
|
+
return config
|
|
31
|
+
}
|
|
32
|
+
|
|
12
33
|
const update_4_25_3 = config => {
|
|
13
34
|
const ver = '4.25.3'
|
|
14
35
|
const newConfig = _.cloneDeep(config)
|
|
15
|
-
|
|
36
|
+
handleVisualizations(newConfig)
|
|
37
|
+
remapTableDownloadCSV(newConfig)
|
|
38
|
+
migrateAreaChart(newConfig)
|
|
16
39
|
newConfig.version = ver
|
|
17
40
|
return newConfig
|
|
18
41
|
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import _ from 'lodash'
|
|
2
|
+
|
|
3
|
+
export const makeChartLegendsUnified = config => {
|
|
4
|
+
if (config.type === 'chart') {
|
|
5
|
+
config.legend = config.legend || {}
|
|
6
|
+
config.legend.unified = true
|
|
7
|
+
} else if (config.type === 'dashboard') {
|
|
8
|
+
Object.values(config.visualizations).forEach(visualization => {
|
|
9
|
+
makeChartLegendsUnified(visualization)
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const migrateTableGeneralSettings = config => {
|
|
15
|
+
if (config.type === 'map') {
|
|
16
|
+
if (config.general.showFullGeoNameInCSV) {
|
|
17
|
+
config.table.showFullGeoNameInCSV = config.general.showFullGeoNameInCSV
|
|
18
|
+
}
|
|
19
|
+
delete config.general.showFullGeoNameInCSV
|
|
20
|
+
return config
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const hasMultipleWidgetColumns = row => {
|
|
25
|
+
const multipleColumns = row.columns.filter(column => column.widget).length > 1
|
|
26
|
+
return multipleColumns && !row.toggle
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const newMarkupIncludeVisualization = (uid, footnotes) => {
|
|
30
|
+
return {
|
|
31
|
+
filters: [],
|
|
32
|
+
filterBehavior: 'Filter Change',
|
|
33
|
+
footnotes,
|
|
34
|
+
uid,
|
|
35
|
+
type: 'markup-include',
|
|
36
|
+
visualizationType: 'markup-include',
|
|
37
|
+
contentEditor: {
|
|
38
|
+
inlineHTML: '',
|
|
39
|
+
markupVariables: [],
|
|
40
|
+
showHeader: false,
|
|
41
|
+
srcUrl: '',
|
|
42
|
+
title: '',
|
|
43
|
+
useInlineHTML: false
|
|
44
|
+
},
|
|
45
|
+
theme: 'theme-blue',
|
|
46
|
+
visual: {
|
|
47
|
+
border: false,
|
|
48
|
+
accent: false,
|
|
49
|
+
background: false,
|
|
50
|
+
hideBackgroundColor: false,
|
|
51
|
+
borderColorTheme: false
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const makeNewRow = uuid => {
|
|
57
|
+
return { columns: [{ width: 12, widget: uuid }] }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const moveFootnotesToVizLevel = config => {
|
|
61
|
+
if (config.type === 'dashboard') {
|
|
62
|
+
const newRowsToAdd = [
|
|
63
|
+
/*old row index*/
|
|
64
|
+
/*new row object*/
|
|
65
|
+
]
|
|
66
|
+
config.rows.forEach((row, index) => {
|
|
67
|
+
if (!row.footnotesId) return
|
|
68
|
+
const makeNewFootnotesRow = hasMultipleWidgetColumns(row)
|
|
69
|
+
const footnotesId = row.footnotesId
|
|
70
|
+
const footnote = _.pick(config.visualizations[footnotesId], ['dataKey', 'dynamicFootnotes', 'staticFootnotes'])
|
|
71
|
+
if (makeNewFootnotesRow) {
|
|
72
|
+
const uuid = `markup-include-${Date.now()}${index}`
|
|
73
|
+
const newRow = makeNewRow(uuid)
|
|
74
|
+
const newFootnotesViz = newMarkupIncludeVisualization(uuid, footnote)
|
|
75
|
+
config.visualizations[uuid] = newFootnotesViz
|
|
76
|
+
newRowsToAdd.push([index, newRow])
|
|
77
|
+
} else {
|
|
78
|
+
row.columns.forEach(column => {
|
|
79
|
+
if (!column.widget) return
|
|
80
|
+
const footnotes = config.visualizations[column.widget].footnotes
|
|
81
|
+
if (typeof footnotes === 'string') {
|
|
82
|
+
// move legacy footnotes
|
|
83
|
+
config.visualizations[column.widget].legacyFootnotes = footnotes
|
|
84
|
+
}
|
|
85
|
+
config.visualizations[column.widget].footnotes = footnote
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
delete config.visualizations[footnotesId]
|
|
90
|
+
delete row.footnotesId
|
|
91
|
+
})
|
|
92
|
+
if (newRowsToAdd.length) {
|
|
93
|
+
newRowsToAdd.forEach(([oldRowIndex, newRow]) => {
|
|
94
|
+
config.rows.splice(oldRowIndex + 1, 0, newRow)
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const update_4_25_4 = config => {
|
|
101
|
+
const ver = '4.25.4'
|
|
102
|
+
const newConfig = _.cloneDeep(config)
|
|
103
|
+
makeChartLegendsUnified(newConfig)
|
|
104
|
+
migrateTableGeneralSettings(newConfig)
|
|
105
|
+
moveFootnotesToVizLevel(newConfig)
|
|
106
|
+
newConfig.version = ver
|
|
107
|
+
return newConfig
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default update_4_25_4
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import _ from 'lodash'
|
|
2
|
+
|
|
3
|
+
// *NOTE: This ends support for only showing the top prefix
|
|
4
|
+
export const changeOnlyShowTopSuffixToInlineLabel = config => {
|
|
5
|
+
if (config.type === 'chart') {
|
|
6
|
+
if (!config.dataFormat?.suffix) return config
|
|
7
|
+
if (!config.dataFormat.onlyShowTopPrefixSuffix) return config
|
|
8
|
+
|
|
9
|
+
delete config.dataFormat.onlyShowTopPrefixSuffix
|
|
10
|
+
|
|
11
|
+
if (!config.yAxis) config.yAxis = {}
|
|
12
|
+
|
|
13
|
+
if (!config.yAxis?.inlineLabel) {
|
|
14
|
+
config.yAxis.inlineLabel = config.dataFormat.suffix
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
config.dataFormat.suffix = ''
|
|
18
|
+
|
|
19
|
+
return config
|
|
20
|
+
} else if (config.type === 'dashboard') {
|
|
21
|
+
Object.values(config.visualizations).forEach(visualization => {
|
|
22
|
+
changeOnlyShowTopSuffixToInlineLabel(visualization)
|
|
23
|
+
})
|
|
24
|
+
return config
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const update_4_25_6 = config => {
|
|
29
|
+
const ver = '4.25.6'
|
|
30
|
+
const newConfig = _.cloneDeep(config)
|
|
31
|
+
changeOnlyShowTopSuffixToInlineLabel(newConfig)
|
|
32
|
+
newConfig.version = ver
|
|
33
|
+
return newConfig
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default update_4_25_6
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import _ from 'lodash'
|
|
2
|
+
|
|
3
|
+
export const updatePreliminaryDataSeriesKeys = config => {
|
|
4
|
+
if (config.type === 'chart') {
|
|
5
|
+
;(config.preliminaryData || []).forEach(pd => {
|
|
6
|
+
if (!pd.seriesKeys) {
|
|
7
|
+
pd.seriesKeys = pd.seriesKey ? [pd.seriesKey] : []
|
|
8
|
+
delete pd.seriesKey
|
|
9
|
+
}
|
|
10
|
+
})
|
|
11
|
+
} else if (config.type === 'dashboard') {
|
|
12
|
+
Object.values(config.visualizations).forEach(visualization => {
|
|
13
|
+
updatePreliminaryDataSeriesKeys(visualization)
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const update_4_25_7 = config => {
|
|
19
|
+
const ver = '4.25.7'
|
|
20
|
+
const newConfig = _.cloneDeep(config)
|
|
21
|
+
updatePreliminaryDataSeriesKeys(newConfig)
|
|
22
|
+
newConfig.version = ver
|
|
23
|
+
return newConfig
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default update_4_25_7
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { expect, describe, it } from 'vitest'
|
|
2
|
+
import { makeChartLegendsUnified, moveFootnotesToVizLevel } from '../4.25.4'
|
|
3
|
+
import { ChartConfig } from '@cdc/chart/src/types/ChartConfig'
|
|
4
|
+
import { DashboardConfig } from '@cdc/dashboard/src/types/DashboardConfig'
|
|
5
|
+
|
|
6
|
+
describe('makeChartLegendsUnified(config) ', () => {
|
|
7
|
+
it('sets chart legends unified to true', () => {
|
|
8
|
+
const mockConfig = { type: 'chart', legend: { unified: false } } as Partial<ChartConfig>
|
|
9
|
+
makeChartLegendsUnified(mockConfig)
|
|
10
|
+
expect(mockConfig.legend?.unified).toBe(true)
|
|
11
|
+
})
|
|
12
|
+
it('sets dashboard nested chart legends unified to true', () => {
|
|
13
|
+
const mockConfig = {
|
|
14
|
+
type: 'dashboard',
|
|
15
|
+
visualizations: {
|
|
16
|
+
'1': { type: 'chart', legend: { unified: false } } as ChartConfig,
|
|
17
|
+
'2': { type: 'chart', legend: { unified: false } } as ChartConfig
|
|
18
|
+
}
|
|
19
|
+
} as Partial<DashboardConfig>
|
|
20
|
+
makeChartLegendsUnified(mockConfig)
|
|
21
|
+
expect(mockConfig.visualizations['1'].legend?.unified).toBe(true)
|
|
22
|
+
expect(mockConfig.visualizations['2'].legend?.unified).toBe(true)
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('moveFootnotesToVizLevel', () => {
|
|
27
|
+
it('moves footnotes to visualization level', () => {
|
|
28
|
+
const toMigrate = {
|
|
29
|
+
rows: [
|
|
30
|
+
{
|
|
31
|
+
columns: [
|
|
32
|
+
{
|
|
33
|
+
width: 12,
|
|
34
|
+
widget: 'table123'
|
|
35
|
+
},
|
|
36
|
+
{},
|
|
37
|
+
{}
|
|
38
|
+
],
|
|
39
|
+
footnotesId: 'footnotes123'
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
visualizations: {
|
|
43
|
+
table123: {},
|
|
44
|
+
footnotes123: {
|
|
45
|
+
uid: 'footnotes123',
|
|
46
|
+
type: 'footnotes',
|
|
47
|
+
visualizationType: 'footnotes',
|
|
48
|
+
dataKey: 'valid-data-chart.csv',
|
|
49
|
+
dynamicFootnotes: {
|
|
50
|
+
symbolColumn: 'Race',
|
|
51
|
+
textColumn: 'Age-adjusted rate'
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
type: 'dashboard',
|
|
56
|
+
version: '4.25.4'
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const expectedMigration = {
|
|
60
|
+
rows: [
|
|
61
|
+
{
|
|
62
|
+
columns: [
|
|
63
|
+
{
|
|
64
|
+
width: 12,
|
|
65
|
+
widget: 'table123'
|
|
66
|
+
},
|
|
67
|
+
{},
|
|
68
|
+
{}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
visualizations: {
|
|
73
|
+
table123: {
|
|
74
|
+
footnotes: {
|
|
75
|
+
dataKey: 'valid-data-chart.csv',
|
|
76
|
+
dynamicFootnotes: {
|
|
77
|
+
symbolColumn: 'Race',
|
|
78
|
+
textColumn: 'Age-adjusted rate'
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
type: 'dashboard',
|
|
84
|
+
version: '4.25.4'
|
|
85
|
+
}
|
|
86
|
+
moveFootnotesToVizLevel(toMigrate)
|
|
87
|
+
expect(toMigrate).toEqual(expectedMigration)
|
|
88
|
+
})
|
|
89
|
+
})
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { expect, describe, it } from 'vitest'
|
|
2
|
+
import { changeOnlyShowTopSuffixToInlineLabel } from '../4.25.6'
|
|
3
|
+
|
|
4
|
+
describe('changeOnlyShowTopSuffixToInlineLabel(config) ', () => {
|
|
5
|
+
it("should'nt change config if no suffix", () => {
|
|
6
|
+
const config = {
|
|
7
|
+
type: 'chart',
|
|
8
|
+
dataFormat: {
|
|
9
|
+
onlyShowTopPrefixSuffix: true,
|
|
10
|
+
suffix: ''
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const newConfig = changeOnlyShowTopSuffixToInlineLabel(config)
|
|
14
|
+
expect(newConfig).toEqual(config)
|
|
15
|
+
})
|
|
16
|
+
it("should't change suffix if onlyShowTopPrefixSuffix is false", () => {
|
|
17
|
+
const config = {
|
|
18
|
+
type: 'chart',
|
|
19
|
+
dataFormat: {
|
|
20
|
+
onlyShowTopPrefixSuffix: false,
|
|
21
|
+
suffix: 'test'
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const newConfig = changeOnlyShowTopSuffixToInlineLabel(config)
|
|
25
|
+
expect(newConfig).toEqual(config)
|
|
26
|
+
})
|
|
27
|
+
it('should change suffix to inlineLabel if onlyShowTopPrefixSuffix is true', () => {
|
|
28
|
+
const config = {
|
|
29
|
+
type: 'chart',
|
|
30
|
+
dataFormat: {
|
|
31
|
+
onlyShowTopPrefixSuffix: true,
|
|
32
|
+
suffix: 'test'
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const newConfig = changeOnlyShowTopSuffixToInlineLabel(config)
|
|
36
|
+
expect(newConfig.yAxis.inlineLabel).toBe('test')
|
|
37
|
+
expect(newConfig.dataFormat.onlyShowTopPrefixSuffix).toBe(undefined)
|
|
38
|
+
expect(newConfig.dataFormat.suffix).toBe('')
|
|
39
|
+
})
|
|
40
|
+
it("should't overwrite existing yAxis inlineLabel", () => {
|
|
41
|
+
const config = {
|
|
42
|
+
type: 'chart',
|
|
43
|
+
dataFormat: {
|
|
44
|
+
onlyShowTopPrefixSuffix: true,
|
|
45
|
+
suffix: 'test'
|
|
46
|
+
},
|
|
47
|
+
yAxis: {
|
|
48
|
+
inlineLabel: 'test2'
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const newConfig = changeOnlyShowTopSuffixToInlineLabel(config)
|
|
52
|
+
expect(newConfig.yAxis.inlineLabel).toBe('test2')
|
|
53
|
+
expect(newConfig.dataFormat.onlyShowTopPrefixSuffix).toBe(undefined)
|
|
54
|
+
expect(newConfig.dataFormat.suffix).toBe('')
|
|
55
|
+
})
|
|
56
|
+
it('should change suffix to inlineLabel for dashboard visualizations', () => {
|
|
57
|
+
const config = {
|
|
58
|
+
type: 'dashboard',
|
|
59
|
+
visualizations: [
|
|
60
|
+
{
|
|
61
|
+
type: 'chart',
|
|
62
|
+
dataFormat: {
|
|
63
|
+
onlyShowTopPrefixSuffix: true,
|
|
64
|
+
suffix: 'test'
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: 'chart',
|
|
69
|
+
dataFormat: {
|
|
70
|
+
onlyShowTopPrefixSuffix: true,
|
|
71
|
+
suffix: 'test2'
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
const newConfig = changeOnlyShowTopSuffixToInlineLabel(config)
|
|
77
|
+
expect(newConfig.visualizations[0].yAxis.inlineLabel).toBe('test')
|
|
78
|
+
expect(newConfig.visualizations[0].dataFormat.onlyShowTopPrefixSuffix).toBe(undefined)
|
|
79
|
+
expect(newConfig.visualizations[0].dataFormat.suffix).toBe('')
|
|
80
|
+
expect(newConfig.visualizations[1].yAxis.inlineLabel).toBe('test2')
|
|
81
|
+
expect(newConfig.visualizations[1].dataFormat.onlyShowTopPrefixSuffix).toBe(undefined)
|
|
82
|
+
expect(newConfig.visualizations[1].dataFormat.suffix).toBe('')
|
|
83
|
+
})
|
|
84
|
+
})
|
package/helpers/viewports.ts
CHANGED
|
@@ -8,3 +8,7 @@ export const isBelowBreakpoint = (breakpoint: ViewportSize, currentViewport: Vie
|
|
|
8
8
|
export const isLegendWrapViewport = currentViewport => isBelowBreakpoint('sm', currentViewport)
|
|
9
9
|
|
|
10
10
|
export const isMobileHeightViewport = currentViewport => isBelowBreakpoint('sm', currentViewport)
|
|
11
|
+
|
|
12
|
+
export const isMobileStateLabelViewport = currentViewport => isBelowBreakpoint('md', currentViewport)
|
|
13
|
+
|
|
14
|
+
export const isMobileTerritoryViewport = currentViewport => isBelowBreakpoint('sm', currentViewport)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdc/core",
|
|
3
|
-
"version": "4.25.
|
|
3
|
+
"version": "4.25.6-1",
|
|
4
4
|
"description": "Core components, styles, hooks, and helpers, for the CDC Open Visualization project",
|
|
5
5
|
"moduleName": "CdcCore",
|
|
6
6
|
"main": "dist/cdccore",
|
|
@@ -21,20 +21,21 @@
|
|
|
21
21
|
},
|
|
22
22
|
"license": "Apache-2.0",
|
|
23
23
|
"dependencies": {
|
|
24
|
+
"dompurify": "^3.2.6",
|
|
24
25
|
"html2canvas": "^1.4.1",
|
|
25
|
-
"json-edit-react": "^1.
|
|
26
|
-
"papaparse": "^5.3.0",
|
|
26
|
+
"json-edit-react": "^1.27.0",
|
|
27
27
|
"prop-types": "^15.8.1",
|
|
28
|
-
"react-accessible-accordion": "^5.0.
|
|
28
|
+
"react-accessible-accordion": "^5.0.1",
|
|
29
29
|
"react-select": "^5.3.1",
|
|
30
30
|
"react-tooltip": "5.8.2-beta.3",
|
|
31
|
-
"
|
|
31
|
+
"sass": "^1.89.2",
|
|
32
|
+
"use-debounce": "^10.0.5"
|
|
32
33
|
},
|
|
33
34
|
"peerDependencies": {
|
|
34
35
|
"react": "^18.2.0",
|
|
35
36
|
"react-dom": "^18.2.0"
|
|
36
37
|
},
|
|
37
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "ac45ee0f1d6a4045648c4e083992fc091795e084",
|
|
38
39
|
"devDependencies": {
|
|
39
40
|
"sass": "^1.79.4"
|
|
40
41
|
}
|
|
@@ -8,6 +8,7 @@ $colors: (
|
|
|
8
8
|
'darkGray': #333,
|
|
9
9
|
'red': #d8000c,
|
|
10
10
|
'white': #fff,
|
|
11
|
+
'silver': #eee,
|
|
11
12
|
|
|
12
13
|
'primary': #005eaa,
|
|
13
14
|
'secondary': #88c3ea,
|
|
@@ -106,4 +107,6 @@ $colors: (
|
|
|
106
107
|
--filter-buttons-font-size: 0.889rem;
|
|
107
108
|
--superTitle-font-size: 0.833rem;
|
|
108
109
|
--title-font-size: 1.222rem;
|
|
110
|
+
--territory-label-font-size: 0.809rem;
|
|
111
|
+
--territory-label-font-size-mobile: 0.556rem;
|
|
109
112
|
}
|
package/styles/_global.scss
CHANGED
package/styles/_reset.scss
CHANGED
package/styles/filters.scss
CHANGED
|
@@ -93,10 +93,6 @@ div.single-filters {
|
|
|
93
93
|
&:focus:not(:focus-visible) {
|
|
94
94
|
outline: none !important;
|
|
95
95
|
}
|
|
96
|
-
&:focus-visible {
|
|
97
|
-
outline: 2px dashed var(--colors-blue-vivid-60, #005ea2) !important;
|
|
98
|
-
outline-offset: 3px;
|
|
99
|
-
}
|
|
100
96
|
|
|
101
97
|
&.tab--active {
|
|
102
98
|
font-weight: 500;
|
package/styles/v2/main.scss
CHANGED
package/types/Axis.ts
CHANGED
|
@@ -17,6 +17,7 @@ export type Axis = {
|
|
|
17
17
|
hideAxis?: boolean
|
|
18
18
|
hideLabel?: boolean
|
|
19
19
|
hideTicks?: boolean
|
|
20
|
+
inlineLabel?: string
|
|
20
21
|
label?: string
|
|
21
22
|
labelOffset?: number
|
|
22
23
|
labelPlacement?: string
|
|
@@ -50,4 +51,5 @@ export type Axis = {
|
|
|
50
51
|
axisBBox: number
|
|
51
52
|
maxValue: string
|
|
52
53
|
sortByRecentDate: boolean
|
|
54
|
+
brushActive: boolean
|
|
53
55
|
}
|