@cdc/core 4.24.11 → 4.24.12-2
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/Alert/components/Alert.tsx +9 -4
- package/components/DataTable/DataTable.tsx +19 -8
- package/components/DataTable/DataTableStandAlone.tsx +3 -3
- package/components/DataTable/components/ExpandCollapse.tsx +1 -1
- package/components/DataTable/components/SortIcon/sort-icon.css +15 -0
- package/components/DataTable/helpers/boxplotCellMatrix.tsx +6 -2
- package/components/DataTable/helpers/getChartCellValue.ts +11 -11
- package/components/EditorPanel/DataTableEditor.tsx +29 -23
- package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +25 -1
- package/components/Filters/Filters.tsx +31 -35
- package/components/Filters/helpers/handleSorting.ts +5 -0
- package/components/Footnotes/FootnotesStandAlone.tsx +17 -4
- package/components/Layout/components/Visualization/visualizations.scss +1 -1
- package/components/Legend/Legend.Gradient.tsx +1 -1
- package/components/Loader/Loader.tsx +10 -5
- package/components/MultiSelect/MultiSelect.tsx +84 -84
- package/components/MultiSelect/multiselect.styles.css +10 -0
- package/components/NestedDropdown/NestedDropdown.tsx +21 -18
- package/components/NestedDropdown/nesteddropdown.styles.css +11 -0
- package/components/Table/components/Row.tsx +1 -1
- package/components/inputs/{InputToggle.jsx → InputToggle.tsx} +35 -29
- package/dist/cove-main.css +6 -3
- package/dist/cove-main.css.map +1 -1
- package/helpers/addValuesToFilters.ts +22 -8
- package/helpers/coveUpdateWorker.ts +1 -1
- package/helpers/filterVizData.ts +2 -2
- package/helpers/formatConfigBeforeSave.ts +15 -0
- package/helpers/gatherQueryParams.ts +2 -3
- package/helpers/queryStringUtils.ts +10 -1
- package/helpers/tests/addValuesToFilters.test.ts +6 -1
- package/helpers/useDataVizClasses.ts +2 -1
- package/helpers/ver/4.24.10.ts +12 -0
- package/helpers/ver/versionNeedsUpdate.ts +2 -0
- package/helpers/viewports.ts +8 -7
- package/package.json +2 -2
- package/styles/_global-variables.scss +8 -3
- package/styles/_reset.scss +0 -1
- package/types/Version.ts +1 -0
- package/types/VizFilter.ts +2 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import _ from 'lodash'
|
|
2
2
|
import { getQueryStringFilterValue } from '@cdc/core/helpers/queryStringUtils'
|
|
3
3
|
import { VizFilter } from '../types/VizFilter'
|
|
4
|
+
import { FILTER_STYLE } from '@cdc/dashboard/src/types/FilterStyles'
|
|
4
5
|
|
|
5
6
|
type Filter = {
|
|
6
7
|
columnName: string
|
|
@@ -28,13 +29,16 @@ const cleanLookup = (lookup: Record<string, { values: string[]; orderedValues?:
|
|
|
28
29
|
// Gets filter values from dataset
|
|
29
30
|
const generateValuesForFilter = (filter: VizFilter, data: any[] | MapData) => {
|
|
30
31
|
const columnName = filter.columnName
|
|
32
|
+
const orderColumn = filter.orderColumn
|
|
31
33
|
const values: string[] = []
|
|
34
|
+
const valuesWithOrders: [string, string][] = []
|
|
32
35
|
const subGroupingColumn = filter.subGrouping?.columnName
|
|
33
36
|
const subValues = cleanLookup(filter.subGrouping?.valuesLookup)
|
|
34
37
|
if (Array.isArray(data)) {
|
|
35
38
|
data.forEach(row => {
|
|
36
|
-
const value = row[columnName]
|
|
39
|
+
const value: string = row[columnName]
|
|
37
40
|
if (value !== undefined && !values.includes(value)) {
|
|
41
|
+
if (orderColumn) valuesWithOrders.push([value, row[orderColumn]])
|
|
38
42
|
values.push(value)
|
|
39
43
|
}
|
|
40
44
|
if (subGroupingColumn) {
|
|
@@ -57,12 +61,23 @@ const generateValuesForFilter = (filter: VizFilter, data: any[] | MapData) => {
|
|
|
57
61
|
rows.forEach(row => {
|
|
58
62
|
const value = row[columnName]
|
|
59
63
|
if (value !== undefined && !values.includes(value)) {
|
|
64
|
+
if (orderColumn) valuesWithOrders.push([value, row[orderColumn]])
|
|
60
65
|
values.push(value)
|
|
61
66
|
}
|
|
62
67
|
})
|
|
63
68
|
})
|
|
64
69
|
}
|
|
65
|
-
|
|
70
|
+
if (orderColumn) {
|
|
71
|
+
filter.values = valuesWithOrders.sort((a, b) => a[1].localeCompare(b[1])).map(([value]) => value)
|
|
72
|
+
} else if (filter.order && filter.order !== 'cust') {
|
|
73
|
+
const sort = (a, b) => {
|
|
74
|
+
const asc = filter.order !== 'desc'
|
|
75
|
+
return String(asc ? a : b).localeCompare(String(asc ? b : a), 'en', { numeric: true })
|
|
76
|
+
}
|
|
77
|
+
filter.values = values.sort(sort)
|
|
78
|
+
} else {
|
|
79
|
+
filter.values = values
|
|
80
|
+
}
|
|
66
81
|
if (subGroupingColumn) {
|
|
67
82
|
filter.subGrouping.valuesLookup = subValues
|
|
68
83
|
}
|
|
@@ -72,7 +87,7 @@ const handleVizParents = (filter: VizFilter, data: any[] | MapData, filtersLooku
|
|
|
72
87
|
let filteredData = Array.isArray(data) ? data : Object.values(data).flat(1)
|
|
73
88
|
filter.parents.forEach(parentKey => {
|
|
74
89
|
const parent = filtersLookup[parentKey]
|
|
75
|
-
if (parent?.filterStyle ===
|
|
90
|
+
if (parent?.filterStyle === FILTER_STYLE.nestedDropdown) {
|
|
76
91
|
const { subGrouping } = parent as VizFilter
|
|
77
92
|
if (subGrouping?.active) {
|
|
78
93
|
filteredData = filteredData.filter(d => {
|
|
@@ -107,11 +122,11 @@ export const addValuesToFilters = (filters: VizFilter[], data: any[] | MapData):
|
|
|
107
122
|
filteredData = handleVizParents(filter as VizFilter, data, filtersLookup)
|
|
108
123
|
}
|
|
109
124
|
generateValuesForFilter(filterCopy, filteredData)
|
|
110
|
-
if (filterCopy.values
|
|
125
|
+
if (filterCopy.values?.length > 0) {
|
|
111
126
|
const queryStringFilterValue = getQueryStringFilterValue(filterCopy)
|
|
112
127
|
if (queryStringFilterValue) {
|
|
113
128
|
filterCopy.active = queryStringFilterValue
|
|
114
|
-
} else if (filterCopy.filterStyle ===
|
|
129
|
+
} else if (filterCopy.filterStyle === FILTER_STYLE.multiSelect) {
|
|
115
130
|
const defaultValues = filterCopy.values
|
|
116
131
|
const active = Array.isArray(filterCopy.active) ? filterCopy.active : [filterCopy.active]
|
|
117
132
|
filterCopy.active = active.filter(val => includes(defaultValues, val))
|
|
@@ -128,12 +143,11 @@ export const addValuesToFilters = (filters: VizFilter[], data: any[] | MapData):
|
|
|
128
143
|
values: filterCopy.subGrouping.valuesLookup[groupName].values
|
|
129
144
|
}
|
|
130
145
|
const queryStringFilterValue = getQueryStringFilterValue(subGroupingFilter)
|
|
131
|
-
const groupActive =
|
|
146
|
+
const groupActive = groupName || filterCopy.values[0]
|
|
132
147
|
const defaultValue = filterCopy.subGrouping.valuesLookup[groupActive as string].values[0]
|
|
133
148
|
// if the value doesn't exist in the subGrouping then return the default
|
|
134
|
-
const filteredLookupValues = Object.values(filterCopy.subGrouping.valuesLookup).flatMap(v => v.values)
|
|
135
149
|
const activeValue = queryStringFilterValue || filterCopy.subGrouping.active
|
|
136
|
-
filterCopy.subGrouping.active =
|
|
150
|
+
filterCopy.subGrouping.active = activeValue || defaultValue
|
|
137
151
|
}
|
|
138
152
|
return filterCopy
|
|
139
153
|
})
|
|
@@ -20,7 +20,7 @@ export const coveUpdateWorker = config => {
|
|
|
20
20
|
['4.24.5', update_4_24_5],
|
|
21
21
|
['4.24.7', update_4_24_7, true],
|
|
22
22
|
['4.24.9', update_4_24_9],
|
|
23
|
-
['4.24.10', update_4_24_10]
|
|
23
|
+
['4.24.10', update_4_24_10, true]
|
|
24
24
|
]
|
|
25
25
|
|
|
26
26
|
versions.forEach(([version, updateFunction, alwaysRun]: [string, UpdateFunction, boolean?]) => {
|
package/helpers/filterVizData.ts
CHANGED
|
@@ -36,9 +36,9 @@ export const filterVizData = (filters: Filter[], data) => {
|
|
|
36
36
|
}
|
|
37
37
|
if (filter.filterStyle === 'nested-dropdown' && filter.subGrouping && add === true) {
|
|
38
38
|
const subGroupActive = filter.subGrouping.active
|
|
39
|
-
const
|
|
39
|
+
const subGroupValue = row[filter.subGrouping.columnName]
|
|
40
40
|
if (subGroupActive === undefined) return
|
|
41
|
-
if (
|
|
41
|
+
if (subGroupValue != subGroupActive) {
|
|
42
42
|
add = false
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -65,6 +65,7 @@ const cleanSharedFilters = (config: DashboardConfig) => {
|
|
|
65
65
|
if (config.dashboard?.sharedFilters) {
|
|
66
66
|
config.dashboard.sharedFilters.forEach((filter, index) => {
|
|
67
67
|
delete config.dashboard.sharedFilters[index].active
|
|
68
|
+
if (filter.subGrouping) delete config.dashboard.sharedFilters[index].subGrouping.active
|
|
68
69
|
if (filter.type === 'urlfilter') {
|
|
69
70
|
delete config.dashboard.sharedFilters[index].values
|
|
70
71
|
}
|
|
@@ -72,6 +73,18 @@ const cleanSharedFilters = (config: DashboardConfig) => {
|
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
const cleanVisualizationFilters = (config: DashboardConfig) => {
|
|
77
|
+
if (config.visualizations) {
|
|
78
|
+
Object.keys(config.visualizations).forEach(vizKey => {
|
|
79
|
+
const vizFilters = config.visualizations[vizKey].filters || []
|
|
80
|
+
vizFilters.forEach((_filter, index) => {
|
|
81
|
+
delete config.visualizations[vizKey].filters[index].active
|
|
82
|
+
delete config.visualizations[vizKey].filters[index].values
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
75
88
|
const removeRuntimeDataURLs = (config: DashboardConfig) => {
|
|
76
89
|
if (config.datasets) {
|
|
77
90
|
Object.keys(config.datasets).forEach(datasetKey => {
|
|
@@ -88,6 +101,7 @@ export const formatConfigBeforeSave = configToStrip => {
|
|
|
88
101
|
cleanDashboardData(strippedConfig.multiDashboards[i])
|
|
89
102
|
cleanSharedFilters(strippedConfig.multiDashboards[i])
|
|
90
103
|
cleanDashboardFootnotes(strippedConfig.multiDashboards[i])
|
|
104
|
+
cleanVisualizationFilters(strippedConfig.multiDashboards[i])
|
|
91
105
|
})
|
|
92
106
|
delete strippedConfig.dashboard
|
|
93
107
|
delete strippedConfig.rows
|
|
@@ -98,6 +112,7 @@ export const formatConfigBeforeSave = configToStrip => {
|
|
|
98
112
|
cleanDashboardData(strippedConfig)
|
|
99
113
|
cleanSharedFilters(strippedConfig)
|
|
100
114
|
cleanDashboardFootnotes(strippedConfig)
|
|
115
|
+
cleanVisualizationFilters(strippedConfig)
|
|
101
116
|
removeRuntimeDataURLs(strippedConfig)
|
|
102
117
|
} else {
|
|
103
118
|
delete strippedConfig.runtime
|
|
@@ -5,9 +5,8 @@ const strip = (paramVal: string) => {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
const isNumber = (value: string) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return !isNaN(parseInt(value))
|
|
8
|
+
// matches int and float and negative numbers
|
|
9
|
+
return String(value).match(/^[-]?[0-9\.]+$/)
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
export const gatherQueryParams = (baseEndpoint: string, params: { key: string; value: string }[]) => {
|
|
@@ -16,11 +16,20 @@ export function getQueryStringFilterValue(filter) {
|
|
|
16
16
|
export function getQueryParams() {
|
|
17
17
|
const queryParams = {}
|
|
18
18
|
for (const [key, value] of Array.from(new URLSearchParams(window.location.search).entries())) {
|
|
19
|
-
queryParams[key] = value
|
|
19
|
+
if (!queryParams[key]) queryParams[key] = value
|
|
20
|
+
else {
|
|
21
|
+
// for multiple values of the same key in the query string
|
|
22
|
+
if (Array.isArray(queryParams[key])) queryParams[key].push(value)
|
|
23
|
+
else queryParams[key] = [queryParams[key], value]
|
|
24
|
+
}
|
|
20
25
|
}
|
|
21
26
|
return queryParams
|
|
22
27
|
}
|
|
23
28
|
|
|
29
|
+
export function getQueryParam(param) {
|
|
30
|
+
return getQueryParams()[param]
|
|
31
|
+
}
|
|
32
|
+
|
|
24
33
|
export function updateQueryString(queryParams) {
|
|
25
34
|
const updateUrl = `${window.location.origin}${window.location.pathname}?${Object.keys(queryParams)
|
|
26
35
|
.map(queryParam => `${queryParam}=${encodeURIComponent(queryParams[queryParam])}`)
|
|
@@ -2,6 +2,7 @@ import _ from 'lodash'
|
|
|
2
2
|
import { VizFilter } from '../../types/VizFilter'
|
|
3
3
|
import { addValuesToFilters } from '../addValuesToFilters'
|
|
4
4
|
import { describe, it, expect, vi } from 'vitest'
|
|
5
|
+
import { FILTER_STYLE } from '@cdc/dashboard/src/types/FilterStyles'
|
|
5
6
|
|
|
6
7
|
describe('addValuesToFilters', () => {
|
|
7
8
|
const parentFilter = { columnName: 'parentColumn', id: 11, active: 'apple', values: [] } as VizFilter
|
|
@@ -36,7 +37,11 @@ describe('addValuesToFilters', () => {
|
|
|
36
37
|
//expect(newFilters[1].values).toEqual([])
|
|
37
38
|
})
|
|
38
39
|
it('works for nested dropdowns', () => {
|
|
39
|
-
const nestedParentFilter = {
|
|
40
|
+
const nestedParentFilter = {
|
|
41
|
+
...parentFilter,
|
|
42
|
+
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
43
|
+
subGrouping: { columnName: 'childColumn' }
|
|
44
|
+
}
|
|
40
45
|
const newFilters = addValuesToFilters([nestedParentFilter], data)
|
|
41
46
|
expect(newFilters[0].values).toEqual(['apple', 'pear'])
|
|
42
47
|
expect(newFilters[0].subGrouping.valuesLookup).toEqual({ apple: { values: ['a', 'b'] }, pear: { values: ['c'] } })
|
|
@@ -85,7 +85,8 @@ export default function useDataVizClasses(config, viewport = null) {
|
|
|
85
85
|
li: ['single-legend-item', 'legend-container__li'],
|
|
86
86
|
title: ['legend-container__title'],
|
|
87
87
|
description: ['legend-container__description'],
|
|
88
|
-
div: [legend?.position === 'bottom' && legend?.singleRow ? 'shape-container single-row' : 'shape-container']
|
|
88
|
+
div: [legend?.position === 'bottom' && legend?.singleRow ? 'shape-container single-row' : 'shape-container'],
|
|
89
|
+
resetButton: ['legend-container__reset-button']
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
return { innerContainerClasses, contentClasses, lineDatapointClass, sparkLineStyles, legendClasses }
|
package/helpers/ver/4.24.10.ts
CHANGED
|
@@ -34,12 +34,24 @@ export const setXAxisLabelOffsetToZero = newConfig => {
|
|
|
34
34
|
newConfig.xAxis.labelOffset = 0
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
export const defineFilterStyles = newConfig => {
|
|
38
|
+
if (newConfig.filters) {
|
|
39
|
+
newConfig.filters = newConfig.filters.map(filter => {
|
|
40
|
+
if (!filter.filterStyle) {
|
|
41
|
+
filter.filterStyle = 'dropdown'
|
|
42
|
+
}
|
|
43
|
+
return filter
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
37
48
|
const update_4_24_10 = config => {
|
|
38
49
|
const ver = '4.24.10'
|
|
39
50
|
const newConfig = _.cloneDeep(config)
|
|
40
51
|
setXAxisLabelOffsetToZero(newConfig)
|
|
41
52
|
changePivotColumns(newConfig)
|
|
42
53
|
removeMultiSelectPropFromMultiselect(newConfig)
|
|
54
|
+
defineFilterStyles(newConfig)
|
|
43
55
|
newConfig.version = ver
|
|
44
56
|
return newConfig
|
|
45
57
|
}
|
package/helpers/viewports.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
return ['xs', 'xxs'].includes(currentViewport)
|
|
3
|
-
}
|
|
1
|
+
import { ViewportSize } from '@cdc/map/src/types/MapConfig'
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
return ['xs', 'xxs'].includes(currentViewport)
|
|
7
|
-
}
|
|
3
|
+
const BREAKPOINTS = ['xxs', 'xs', 'sm', 'md', 'lg']
|
|
8
4
|
|
|
9
|
-
export
|
|
5
|
+
export const isBelowBreakpoint = (breakpoint: ViewportSize, currentViewport: ViewportSize) =>
|
|
6
|
+
BREAKPOINTS.indexOf(currentViewport) < BREAKPOINTS.indexOf(breakpoint)
|
|
7
|
+
|
|
8
|
+
export const isLegendWrapViewport = currentViewport => isBelowBreakpoint('sm', currentViewport)
|
|
9
|
+
|
|
10
|
+
export const isMobileHeightViewport = currentViewport => isBelowBreakpoint('sm', currentViewport)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdc/core",
|
|
3
|
-
"version": "4.24.
|
|
3
|
+
"version": "4.24.12-2",
|
|
4
4
|
"description": "Core components, styles, hooks, and helpers, for the CDC Open Visualization project",
|
|
5
5
|
"moduleName": "CdcCore",
|
|
6
6
|
"main": "dist/cdccore",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"react": "^18.2.0",
|
|
35
35
|
"react-dom": "^18.2.0"
|
|
36
36
|
},
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "a60edf1148396309eb473ac9f65426ee40797ddf",
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"sass": "^1.79.4"
|
|
40
40
|
}
|
|
@@ -62,7 +62,12 @@ $colors: (
|
|
|
62
62
|
'amber-primary': #fbab18,
|
|
63
63
|
'amber-secondary': #ffd54f,
|
|
64
64
|
'amber-tertiary': #ffecb3,
|
|
65
|
-
'amber-quaternary': #fff7e1
|
|
65
|
+
'amber-quaternary': #fff7e1,
|
|
66
|
+
|
|
67
|
+
'cool-gray-90': #1c1d1f,
|
|
68
|
+
'cool-gray-50': #71767a,
|
|
69
|
+
'cool-gray-30': #a9aeb1,
|
|
70
|
+
'cool-gray-10': #dfe1e2
|
|
66
71
|
);
|
|
67
72
|
|
|
68
73
|
@mixin theme() {
|
|
@@ -86,8 +91,8 @@ $colors: (
|
|
|
86
91
|
--font-size: 17px;
|
|
87
92
|
}
|
|
88
93
|
|
|
89
|
-
@media (max-width:
|
|
94
|
+
@media (max-width: 576px) {
|
|
90
95
|
:root {
|
|
91
|
-
--font-size:
|
|
96
|
+
--font-size: 13px;
|
|
92
97
|
}
|
|
93
98
|
}
|
package/styles/_reset.scss
CHANGED
package/types/Version.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type version = `${number}.${number}.${number}`
|
package/types/VizFilter.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type OrderBy = 'asc' | 'desc' | 'cust'
|
|
1
|
+
export type OrderBy = 'asc' | 'desc' | 'cust' | 'column'
|
|
2
2
|
|
|
3
3
|
export type FilterBase = {
|
|
4
4
|
columnName: string
|
|
@@ -23,6 +23,7 @@ export type GeneralFilter = FilterBase & {
|
|
|
23
23
|
filterStyle: VizFilterStyle
|
|
24
24
|
label: string
|
|
25
25
|
order: OrderBy
|
|
26
|
+
orderColumn?: string
|
|
26
27
|
orderedValues?: string[] // should only exist if the order is 'cust'
|
|
27
28
|
queryParameter: string
|
|
28
29
|
setByQueryParameter: string
|