@cdc/core 4.24.7 → 4.24.9-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/LICENSE +201 -0
- package/assets/icon-gear-multi.svg +23 -0
- package/components/Alert/components/Alert.styles.css +15 -0
- package/components/Alert/components/Alert.tsx +39 -0
- package/components/Alert/index.tsx +3 -0
- package/components/DataTable/DataTable.tsx +106 -30
- package/components/DataTable/helpers/chartCellMatrix.tsx +3 -3
- package/components/DataTable/helpers/getChartCellValue.ts +1 -1
- package/components/DataTable/helpers/getDataSeriesColumns.ts +2 -2
- package/components/DataTable/helpers/mapCellMatrix.tsx +3 -3
- package/components/DataTable/types/TableConfig.ts +1 -1
- package/components/EditorPanel/Inputs.tsx +13 -4
- package/components/EditorPanel/VizFilterEditor/NestedDropdownEditor.tsx +268 -0
- package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +161 -82
- package/components/EditorPanel/VizFilterEditor/components/FilterOrder.tsx +31 -45
- package/components/Filters.tsx +223 -180
- package/components/Layout/components/Responsive.tsx +14 -4
- package/components/Layout/components/Sidebar/components/Sidebar.tsx +14 -5
- package/components/Layout/components/Sidebar/components/sidebar.styles.scss +15 -16
- package/components/Layout/components/Visualization/index.tsx +7 -1
- package/components/Layout/components/Visualization/visualizations.scss +32 -26
- package/components/Layout/styles/editor.scss +0 -8
- package/components/Legend/Legend.Gradient.tsx +133 -0
- package/components/LegendShape.tsx +28 -0
- package/components/MultiSelect/MultiSelect.tsx +6 -3
- package/components/NestedDropdown/NestedDropdown.tsx +47 -52
- package/components/NestedDropdown/nesteddropdown.styles.css +19 -25
- package/components/Table/Table.tsx +8 -5
- package/components/Table/components/Cell.tsx +2 -2
- package/components/Table/components/Row.tsx +25 -7
- package/components/_stories/Layout.Debug.stories.tsx +91 -0
- package/components/_stories/_mocks/bar-chart-suppressed.json +474 -0
- package/components/_stories/styles.scss +13 -1
- package/components/createBarElement.jsx +4 -4
- package/components/ui/Icon.tsx +21 -14
- package/components/ui/Title/Title.scss +0 -8
- package/helpers/DataTransform.ts +2 -2
- package/helpers/addValuesToFilters.ts +95 -16
- package/helpers/cove/accessibility.ts +16 -4
- package/helpers/coveUpdateWorker.ts +24 -10
- package/helpers/filterVizData.ts +23 -4
- package/helpers/formatConfigBeforeSave.ts +22 -2
- package/helpers/gatherQueryParams.ts +12 -2
- package/helpers/getGradientLegendWidth.ts +15 -0
- package/helpers/getTextWidth.ts +18 -0
- package/helpers/scaling.ts +7 -0
- package/helpers/tests/addValuesToFilters.test.ts +55 -0
- package/helpers/tests/filterVizData.test.ts +31 -0
- package/helpers/tests/gatherQueryParams.test.ts +22 -0
- package/helpers/tests/invertValue.test.ts +35 -0
- package/helpers/updatePaletteNames.ts +19 -0
- package/helpers/{useDataVizClasses.js → useDataVizClasses.ts} +3 -2
- package/helpers/ver/4.24.5.ts +3 -3
- package/helpers/ver/4.24.7.ts +34 -3
- package/helpers/ver/4.24.9.ts +63 -0
- package/helpers/ver/tests/4.24.9.test.ts +22 -0
- package/helpers/ver/versionNeedsUpdate.ts +9 -0
- package/package.json +3 -3
- package/styles/_button-section.scss +1 -1
- package/styles/_global.scss +6 -2
- package/styles/filters.scss +4 -0
- package/types/Axis.ts +3 -0
- package/types/Dimensions.ts +1 -0
- package/types/General.ts +1 -1
- package/types/VizFilter.ts +24 -3
- package/components/LegendCircle.jsx +0 -17
- package/helpers/updatePaletteNames.js +0 -16
- /package/components/{Waiting.jsx → Waiting.tsx} +0 -0
- /package/helpers/ver/{4.23.4.ts → 4.24.4.ts} +0 -0
|
@@ -1,53 +1,39 @@
|
|
|
1
|
-
import { VizFilter } from '../../../../types/VizFilter'
|
|
2
|
-
import { filterOrderOptions } from '../../../Filters'
|
|
3
1
|
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd'
|
|
4
2
|
|
|
5
3
|
type FilterOrderProps = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
updateFilterProp: (prop: string, index: number, value: string) => void
|
|
9
|
-
handleFilterOrder: (sourceIndex: number, destinationIndex: number, filterIndex: number, filter: VizFilter) => void
|
|
4
|
+
orderedValues: string[]
|
|
5
|
+
handleFilterOrder?: (index1: number, index2: number) => void
|
|
10
6
|
}
|
|
11
|
-
|
|
12
|
-
const FilterOrder: React.FC<FilterOrderProps> = ({ filterIndex, filter, updateFilterProp, handleFilterOrder }) => {
|
|
7
|
+
const FilterOrder: React.FC<FilterOrderProps> = ({ orderedValues, handleFilterOrder }) => {
|
|
13
8
|
return (
|
|
14
|
-
<
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
)
|
|
43
|
-
})}
|
|
44
|
-
{provided.placeholder}
|
|
45
|
-
</ul>
|
|
46
|
-
)}
|
|
47
|
-
</Droppable>
|
|
48
|
-
</DragDropContext>
|
|
49
|
-
)}
|
|
50
|
-
</label>
|
|
9
|
+
<DragDropContext onDragEnd={({ source, destination }) => handleFilterOrder(source?.index, destination?.index)}>
|
|
10
|
+
<Droppable droppableId='filter_order'>
|
|
11
|
+
{provided => (
|
|
12
|
+
<ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
|
|
13
|
+
{orderedValues?.map((value, index) => {
|
|
14
|
+
return (
|
|
15
|
+
<Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
|
|
16
|
+
{(provided, snapshot) => (
|
|
17
|
+
<li>
|
|
18
|
+
<div
|
|
19
|
+
className={snapshot.isDragging ? 'currently-dragging' : ''}
|
|
20
|
+
style={provided.draggableProps.style}
|
|
21
|
+
ref={provided.innerRef}
|
|
22
|
+
{...provided.draggableProps}
|
|
23
|
+
{...provided.dragHandleProps}
|
|
24
|
+
>
|
|
25
|
+
{value}
|
|
26
|
+
</div>
|
|
27
|
+
</li>
|
|
28
|
+
)}
|
|
29
|
+
</Draggable>
|
|
30
|
+
)
|
|
31
|
+
})}
|
|
32
|
+
{provided.placeholder}
|
|
33
|
+
</ul>
|
|
34
|
+
)}
|
|
35
|
+
</Droppable>
|
|
36
|
+
</DragDropContext>
|
|
51
37
|
)
|
|
52
38
|
}
|
|
53
39
|
|
package/components/Filters.tsx
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react'
|
|
1
|
+
import { useState, useEffect, useMemo } from 'react'
|
|
2
2
|
import { useId } from 'react'
|
|
3
3
|
|
|
4
4
|
// CDC
|
|
5
5
|
import Button from './elements/Button'
|
|
6
6
|
import { getQueryParams, updateQueryString } from '../helpers/queryStringUtils'
|
|
7
|
-
|
|
8
|
-
// Third Party
|
|
9
|
-
import PropTypes from 'prop-types'
|
|
10
7
|
import MultiSelect from './MultiSelect'
|
|
11
8
|
import { Visualization } from '../types/Visualization'
|
|
12
|
-
import { MultiSelectFilter, VizFilter } from '../types/VizFilter'
|
|
9
|
+
import { MultiSelectFilter, OrderBy, VizFilter } from '../types/VizFilter'
|
|
13
10
|
import { filterVizData } from '../helpers/filterVizData'
|
|
14
11
|
import { addValuesToFilters } from '../helpers/addValuesToFilters'
|
|
12
|
+
import { DimensionsType } from '../types/Dimensions'
|
|
13
|
+
import NestedDropdown from './NestedDropdown'
|
|
14
|
+
import _ from 'lodash'
|
|
15
15
|
|
|
16
|
-
export const filterStyleOptions = ['dropdown', 'pill', 'tab', 'tab bar', 'multi-select']
|
|
16
|
+
export const filterStyleOptions = ['dropdown', 'nested-dropdown', 'pill', 'tab', 'tab bar', 'multi-select']
|
|
17
17
|
|
|
18
|
-
export const filterOrderOptions = [
|
|
18
|
+
export const filterOrderOptions: { label: string; value: OrderBy }[] = [
|
|
19
19
|
{
|
|
20
20
|
label: 'Ascending Alphanumeric',
|
|
21
21
|
value: 'asc'
|
|
@@ -31,27 +31,19 @@ export const filterOrderOptions = [
|
|
|
31
31
|
]
|
|
32
32
|
|
|
33
33
|
export const handleSorting = singleFilter => {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return
|
|
34
|
+
const singleFilterValues = _.cloneDeep(singleFilter.values)
|
|
35
|
+
if (singleFilter.order === 'cust' && singleFilter.filterStyle !== 'nested-dropdown') {
|
|
36
|
+
singleFilter.values = singleFilter.orderedValues?.length ? singleFilter.orderedValues : singleFilterValues
|
|
37
|
+
return singleFilter
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
const
|
|
41
|
-
|
|
40
|
+
const sort = (a, b) => {
|
|
41
|
+
const asc = singleFilter.order !== 'desc'
|
|
42
|
+
return (asc ? a : b).toString().localeCompare((asc ? b : a).toString(), 'en', { numeric: true })
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
singleFilter.order = 'asc'
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (order === 'desc') {
|
|
49
|
-
singleFilter.values = singleFilter.values.sort(sortDesc)
|
|
50
|
-
}
|
|
45
|
+
singleFilter.values = singleFilterValues.sort(sort)
|
|
51
46
|
|
|
52
|
-
if (order === 'asc') {
|
|
53
|
-
singleFilter.values = singleFilter.values.sort(sortAsc)
|
|
54
|
-
}
|
|
55
47
|
return singleFilter
|
|
56
48
|
}
|
|
57
49
|
|
|
@@ -83,7 +75,9 @@ export const useFilters = props => {
|
|
|
83
75
|
const [movedItem] = updatedValues.splice(idx1, 1)
|
|
84
76
|
updatedValues.splice(idx2, 0, movedItem)
|
|
85
77
|
|
|
86
|
-
const filtersCopy = hasStandardFilterBehavior.includes(visualizationConfig.type)
|
|
78
|
+
const filtersCopy = hasStandardFilterBehavior.includes(visualizationConfig.type)
|
|
79
|
+
? [...visualizationConfig.filters]
|
|
80
|
+
: [...filteredData]
|
|
87
81
|
const filterItem = { ...filtersCopy[filterIndex] }
|
|
88
82
|
|
|
89
83
|
// Overwrite filterItem.values since thats what we map through in the editor panel
|
|
@@ -102,17 +96,20 @@ export const useFilters = props => {
|
|
|
102
96
|
setConfig({ ...visualizationConfig, filters: filtersCopy })
|
|
103
97
|
}
|
|
104
98
|
|
|
105
|
-
const announceChange = text => {}
|
|
106
|
-
|
|
107
99
|
const changeFilterActive = (index, value) => {
|
|
108
|
-
|
|
100
|
+
let newFilters = visualizationConfig.type === 'map' ? [...filteredData] : [...visualizationConfig.filters]
|
|
109
101
|
|
|
110
102
|
if (visualizationConfig.filterBehavior === 'Apply Button') {
|
|
111
103
|
newFilters[index].queuedActive = value
|
|
112
104
|
setShowApplyButton(true)
|
|
113
105
|
} else {
|
|
114
106
|
const newFilter = newFilters[index]
|
|
115
|
-
newFilter.
|
|
107
|
+
if (newFilter.filterStyle !== 'nested-dropdown') {
|
|
108
|
+
newFilter.active = value
|
|
109
|
+
} else {
|
|
110
|
+
newFilter.active = value[0]
|
|
111
|
+
newFilter.subGrouping.active = value[1]
|
|
112
|
+
}
|
|
116
113
|
|
|
117
114
|
const queryParams = getQueryParams()
|
|
118
115
|
if (newFilter.setByQueryParameter && queryParams[newFilter.setByQueryParameter] !== newFilter.active) {
|
|
@@ -120,10 +117,14 @@ export const useFilters = props => {
|
|
|
120
117
|
updateQueryString(queryParams)
|
|
121
118
|
}
|
|
122
119
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
120
|
+
|
|
121
|
+
if (!visualizationConfig.dynamicSeries) {
|
|
122
|
+
newFilters = addValuesToFilters(newFilters, excludedData)
|
|
123
|
+
setConfig({
|
|
124
|
+
...visualizationConfig,
|
|
125
|
+
filters: newFilters
|
|
126
|
+
})
|
|
127
|
+
}
|
|
127
128
|
|
|
128
129
|
// Used for setting active filter, fromHash breaks the filteredData functionality.
|
|
129
130
|
if (visualizationConfig.type === 'map' && visualizationConfig.filterBehavior === 'Filter Change') {
|
|
@@ -131,8 +132,52 @@ export const useFilters = props => {
|
|
|
131
132
|
}
|
|
132
133
|
|
|
133
134
|
// If we're on a chart and not using the apply button
|
|
134
|
-
if (
|
|
135
|
-
|
|
135
|
+
if (
|
|
136
|
+
hasStandardFilterBehavior.includes(visualizationConfig.type) &&
|
|
137
|
+
visualizationConfig.filterBehavior === 'Filter Change'
|
|
138
|
+
) {
|
|
139
|
+
const newFilteredData = filterVizData(newFilters, excludedData)
|
|
140
|
+
setFilteredData(newFilteredData)
|
|
141
|
+
|
|
142
|
+
if (visualizationConfig.dynamicSeries) {
|
|
143
|
+
const runtime = visualizationConfig.runtime || {}
|
|
144
|
+
runtime.series = []
|
|
145
|
+
runtime.seriesLabels = {}
|
|
146
|
+
runtime.seriesLabelsAll = []
|
|
147
|
+
|
|
148
|
+
if (newFilteredData && newFilteredData.length && newFilteredData.length > 0) {
|
|
149
|
+
Object.keys(newFilteredData[0]).forEach(seriesKey => {
|
|
150
|
+
if (
|
|
151
|
+
seriesKey !== visualizationConfig.xAxis.dataKey &&
|
|
152
|
+
newFilteredData[0][seriesKey] &&
|
|
153
|
+
(!visualizationConfig.filters ||
|
|
154
|
+
visualizationConfig.filters?.filter(filter => filter.columnName === seriesKey).length === 0) &&
|
|
155
|
+
(!visualizationConfig.columns || Object.keys(visualizationConfig.columns).indexOf(seriesKey) === -1)
|
|
156
|
+
) {
|
|
157
|
+
runtime.series.push({
|
|
158
|
+
dataKey: seriesKey,
|
|
159
|
+
type: visualizationConfig.dynamicSeriesType,
|
|
160
|
+
lineType: visualizationConfig.dynamicSeriesLineType,
|
|
161
|
+
tooltip: true
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
runtime.seriesKeys = runtime.series
|
|
168
|
+
? runtime.series.map(series => {
|
|
169
|
+
runtime.seriesLabels[series.dataKey] = series.name || series.label || series.dataKey
|
|
170
|
+
runtime.seriesLabelsAll.push(series.name || series.dataKey)
|
|
171
|
+
return series.dataKey
|
|
172
|
+
})
|
|
173
|
+
: []
|
|
174
|
+
|
|
175
|
+
setConfig({
|
|
176
|
+
...visualizationConfig,
|
|
177
|
+
filters: newFilters,
|
|
178
|
+
runtime
|
|
179
|
+
})
|
|
180
|
+
}
|
|
136
181
|
}
|
|
137
182
|
}
|
|
138
183
|
|
|
@@ -209,7 +254,6 @@ export const useFilters = props => {
|
|
|
209
254
|
return {
|
|
210
255
|
handleApplyButton,
|
|
211
256
|
changeFilterActive,
|
|
212
|
-
announceChange,
|
|
213
257
|
showApplyButton,
|
|
214
258
|
handleReset,
|
|
215
259
|
filterConstants,
|
|
@@ -221,9 +265,15 @@ export const useFilters = props => {
|
|
|
221
265
|
}
|
|
222
266
|
|
|
223
267
|
type FilterProps = {
|
|
224
|
-
filteredData
|
|
225
|
-
dimensions
|
|
268
|
+
filteredData: Object[]
|
|
269
|
+
dimensions: DimensionsType
|
|
226
270
|
config: Visualization
|
|
271
|
+
// function for updating the runtime filters
|
|
272
|
+
setFilteredData: Function
|
|
273
|
+
// updating function for setting fitlerBehavior
|
|
274
|
+
setConfig: Function
|
|
275
|
+
// exclusions
|
|
276
|
+
exclusions: any[]
|
|
227
277
|
}
|
|
228
278
|
|
|
229
279
|
const Filters = (props: FilterProps) => {
|
|
@@ -238,7 +288,6 @@ const Filters = (props: FilterProps) => {
|
|
|
238
288
|
const {
|
|
239
289
|
handleApplyButton,
|
|
240
290
|
changeFilterActive,
|
|
241
|
-
announceChange,
|
|
242
291
|
showApplyButton,
|
|
243
292
|
handleReset,
|
|
244
293
|
filterConstants,
|
|
@@ -247,7 +296,7 @@ const Filters = (props: FilterProps) => {
|
|
|
247
296
|
|
|
248
297
|
useEffect(() => {
|
|
249
298
|
if (!dimensions) return
|
|
250
|
-
if (dimensions[0] < 768 && filters?.length > 0) {
|
|
299
|
+
if (Number(dimensions[0]) < 768 && filters?.length > 0) {
|
|
251
300
|
setMobileFilterStyle(true)
|
|
252
301
|
} else {
|
|
253
302
|
setMobileFilterStyle(false)
|
|
@@ -261,40 +310,7 @@ const Filters = (props: FilterProps) => {
|
|
|
261
310
|
}
|
|
262
311
|
}, [changeFilterActive, selectedFilter])
|
|
263
312
|
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
const filterSectionClassList = ['filters-section', type === 'map' ? general.headerColor : visualizationConfig?.visualizationType === 'Spark Line' ? null : theme]
|
|
267
|
-
// Exterior Section Wrapper
|
|
268
|
-
Filters.Section = ({ children }) => {
|
|
269
|
-
return (
|
|
270
|
-
visualizationConfig?.filters && (
|
|
271
|
-
<section className={filterSectionClassList.join(' ')}>
|
|
272
|
-
<p className='filters-section__intro-text'>
|
|
273
|
-
{filters?.some(f => f.active) ? filterConstants.introText : ''} {visualizationConfig.filterBehavior === 'Apply Button' && filterConstants.applyText}
|
|
274
|
-
</p>
|
|
275
|
-
<div className='filters-section__wrapper'>{children}</div>
|
|
276
|
-
</section>
|
|
277
|
-
)
|
|
278
|
-
)
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Apply/Reset Buttons
|
|
282
|
-
Filters.ApplyBehavior = () => {
|
|
283
|
-
if (filterBehavior !== 'Apply Button') return
|
|
284
|
-
const applyButtonClasses = [general?.headerColor ? general.headerColor : theme, 'apply']
|
|
285
|
-
return (
|
|
286
|
-
<div className='filters-section__buttons'>
|
|
287
|
-
<Button onClick={() => handleApplyButton(filters)} disabled={!showApplyButton} className={applyButtonClasses.join(' ')}>
|
|
288
|
-
{filterConstants.buttonText}
|
|
289
|
-
</Button>
|
|
290
|
-
<a href='#!' role='button' onClick={handleReset}>
|
|
291
|
-
{filterConstants.resetText}
|
|
292
|
-
</a>
|
|
293
|
-
</div>
|
|
294
|
-
)
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
Filters.TabBar = props => {
|
|
313
|
+
const TabBar = props => {
|
|
298
314
|
const { filter: singleFilter, index: outerIndex } = props
|
|
299
315
|
return (
|
|
300
316
|
<section className='single-filters__tab-bar'>
|
|
@@ -324,11 +340,7 @@ const Filters = (props: FilterProps) => {
|
|
|
324
340
|
)
|
|
325
341
|
}
|
|
326
342
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
Filters.Tabs = props => props.tabs
|
|
330
|
-
|
|
331
|
-
Filters.Dropdown = props => {
|
|
343
|
+
const Dropdown = props => {
|
|
332
344
|
const { index: outerIndex, label, active, filters } = props
|
|
333
345
|
return (
|
|
334
346
|
<select
|
|
@@ -340,7 +352,6 @@ const Filters = (props: FilterProps) => {
|
|
|
340
352
|
value={active}
|
|
341
353
|
onChange={e => {
|
|
342
354
|
changeFilterActive(outerIndex, e.target.value)
|
|
343
|
-
announceChange(`Filter ${label} value has been changed to ${e.target.value}, please reference the data table to see updated values.`)
|
|
344
355
|
}}
|
|
345
356
|
>
|
|
346
357
|
{filters}
|
|
@@ -348,130 +359,162 @@ const Filters = (props: FilterProps) => {
|
|
|
348
359
|
)
|
|
349
360
|
}
|
|
350
361
|
|
|
362
|
+
const vizFiltersWithValues = useMemo(() => {
|
|
363
|
+
// Here charts is using config.filters where maps is using a runtime value
|
|
364
|
+
let vizfilters = type === 'map' ? filteredData : filters
|
|
365
|
+
if (!vizfilters) return []
|
|
366
|
+
if (vizfilters.fromHash) delete vizfilters.fromHash // support for Maps config
|
|
367
|
+
return addValuesToFilters(vizfilters as VizFilter[], visualizationConfig.data)
|
|
368
|
+
}, [filters, filteredData])
|
|
369
|
+
|
|
351
370
|
// Resolve Filter Styles
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
let filtersToLoop = type === 'map' ? filteredData : filters
|
|
356
|
-
|
|
357
|
-
// Remove fromHash if it exists on filters to loop so we can loop nicely
|
|
358
|
-
delete filtersToLoop.fromHash
|
|
359
|
-
|
|
360
|
-
return addValuesToFilters<VizFilter>(filtersToLoop, visualizationConfig.data).map((singleFilter: VizFilter, outerIndex) => {
|
|
361
|
-
if (singleFilter.showDropdown === false) return
|
|
362
|
-
|
|
363
|
-
const values = []
|
|
364
|
-
const pillValues = []
|
|
365
|
-
const tabValues = []
|
|
366
|
-
const tabBarValues = []
|
|
367
|
-
|
|
368
|
-
const { active, queuedActive, label, filterStyle } = singleFilter as VizFilter
|
|
369
|
-
|
|
370
|
-
handleSorting(singleFilter)
|
|
371
|
-
|
|
372
|
-
singleFilter.values?.forEach((filterOption, index) => {
|
|
373
|
-
const pillClassList = ['pill', active === filterOption ? 'pill--active' : null, theme && theme]
|
|
374
|
-
const tabClassList = ['tab', active === filterOption && 'tab--active', theme && theme]
|
|
375
|
-
|
|
376
|
-
pillValues.push(
|
|
377
|
-
<div className='pill__wrapper' key={`pill-${index}`}>
|
|
378
|
-
<button
|
|
379
|
-
id={`${filterOption}-${outerIndex}-${index}-${id}`}
|
|
380
|
-
className={pillClassList.join(' ')}
|
|
381
|
-
onKeyDown={e => {
|
|
382
|
-
if (e.keyCode === 13) {
|
|
383
|
-
changeFilterActive(outerIndex, filterOption)
|
|
384
|
-
setSelectedFilter(e.target)
|
|
385
|
-
}
|
|
386
|
-
}}
|
|
387
|
-
onClick={e => {
|
|
388
|
-
changeFilterActive(outerIndex, filterOption)
|
|
389
|
-
setSelectedFilter(e.target)
|
|
390
|
-
}}
|
|
391
|
-
name={label}
|
|
392
|
-
>
|
|
393
|
-
{filterOption}
|
|
394
|
-
</button>
|
|
395
|
-
</div>
|
|
396
|
-
)
|
|
371
|
+
const Style = () => {
|
|
372
|
+
return vizFiltersWithValues.map((singleFilter: VizFilter, outerIndex) => {
|
|
373
|
+
if (singleFilter.showDropdown === false) return
|
|
397
374
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
375
|
+
const DropdownOptions = []
|
|
376
|
+
const Pills = []
|
|
377
|
+
const Tabs = []
|
|
378
|
+
|
|
379
|
+
const { active, queuedActive, label, filterStyle } = singleFilter as VizFilter
|
|
403
380
|
|
|
404
|
-
|
|
381
|
+
handleSorting(singleFilter)
|
|
382
|
+
|
|
383
|
+
singleFilter.values?.forEach((filterOption, index) => {
|
|
384
|
+
const pillClassList = ['pill', active === filterOption ? 'pill--active' : null, theme && theme]
|
|
385
|
+
const tabClassList = ['tab', active === filterOption && 'tab--active', theme && theme]
|
|
386
|
+
|
|
387
|
+
Pills.push(
|
|
388
|
+
<div className='pill__wrapper' key={`pill-${index}`}>
|
|
405
389
|
<button
|
|
406
390
|
id={`${filterOption}-${outerIndex}-${index}-${id}`}
|
|
407
|
-
className={
|
|
408
|
-
onClick={e => {
|
|
409
|
-
changeFilterActive(outerIndex, filterOption)
|
|
410
|
-
setSelectedFilter(e.target)
|
|
411
|
-
}}
|
|
391
|
+
className={pillClassList.join(' ')}
|
|
412
392
|
onKeyDown={e => {
|
|
413
393
|
if (e.keyCode === 13) {
|
|
414
394
|
changeFilterActive(outerIndex, filterOption)
|
|
415
395
|
setSelectedFilter(e.target)
|
|
416
396
|
}
|
|
417
397
|
}}
|
|
398
|
+
onClick={e => {
|
|
399
|
+
changeFilterActive(outerIndex, filterOption)
|
|
400
|
+
setSelectedFilter(e.target)
|
|
401
|
+
}}
|
|
402
|
+
name={label}
|
|
418
403
|
>
|
|
419
404
|
{filterOption}
|
|
420
405
|
</button>
|
|
421
|
-
|
|
406
|
+
</div>
|
|
407
|
+
)
|
|
422
408
|
|
|
423
|
-
|
|
424
|
-
|
|
409
|
+
DropdownOptions.push(
|
|
410
|
+
<option key={index} value={filterOption} aria-label={filterOption}>
|
|
411
|
+
{singleFilter.labels && singleFilter.labels[filterOption]
|
|
412
|
+
? singleFilter.labels[filterOption]
|
|
413
|
+
: filterOption}
|
|
414
|
+
</option>
|
|
415
|
+
)
|
|
425
416
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
/>
|
|
444
|
-
)}
|
|
445
|
-
</>
|
|
446
|
-
</div>
|
|
417
|
+
Tabs.push(
|
|
418
|
+
<button
|
|
419
|
+
id={`${filterOption}-${outerIndex}-${index}-${id}`}
|
|
420
|
+
className={tabClassList.join(' ')}
|
|
421
|
+
onClick={e => {
|
|
422
|
+
changeFilterActive(outerIndex, filterOption)
|
|
423
|
+
setSelectedFilter(e.target)
|
|
424
|
+
}}
|
|
425
|
+
onKeyDown={e => {
|
|
426
|
+
if (e.keyCode === 13) {
|
|
427
|
+
changeFilterActive(outerIndex, filterOption)
|
|
428
|
+
setSelectedFilter(e.target)
|
|
429
|
+
}
|
|
430
|
+
}}
|
|
431
|
+
>
|
|
432
|
+
{filterOption}
|
|
433
|
+
</button>
|
|
447
434
|
)
|
|
448
435
|
})
|
|
449
|
-
|
|
436
|
+
|
|
437
|
+
const classList = [
|
|
438
|
+
'single-filters',
|
|
439
|
+
mobileFilterStyle ? 'single-filters--dropdown' : `single-filters--${filterStyle}`
|
|
440
|
+
]
|
|
441
|
+
const mobileExempt = ['nested-dropdown', 'multi-select'].includes(filterStyle)
|
|
442
|
+
const showDefaultDropdown = (filterStyle === 'dropdown' || mobileFilterStyle) && !mobileExempt
|
|
443
|
+
return (
|
|
444
|
+
<div className={classList.join(' ')} key={outerIndex}>
|
|
445
|
+
<>
|
|
446
|
+
{label && <label htmlFor={`filter-${outerIndex}`}>{label}</label>}
|
|
447
|
+
{filterStyle === 'tab' && !mobileFilterStyle && Tabs}
|
|
448
|
+
{filterStyle === 'pill' && !mobileFilterStyle && Pills}
|
|
449
|
+
{filterStyle === 'tab bar' && !mobileFilterStyle && <TabBar filter={singleFilter} index={outerIndex} />}
|
|
450
|
+
{filterStyle === 'multi-select' && (
|
|
451
|
+
<MultiSelect
|
|
452
|
+
options={singleFilter.values.map(v => ({ value: v, label: v }))}
|
|
453
|
+
fieldName={outerIndex}
|
|
454
|
+
updateField={(_section, _subSection, fieldName, value) => changeFilterActive(fieldName, value)}
|
|
455
|
+
selected={singleFilter.active as string[]}
|
|
456
|
+
limit={(singleFilter as MultiSelectFilter).selectLimit || 5}
|
|
457
|
+
/>
|
|
458
|
+
)}
|
|
459
|
+
{filterStyle === 'nested-dropdown' && (
|
|
460
|
+
<NestedDropdown
|
|
461
|
+
currentFilter={singleFilter}
|
|
462
|
+
listLabel={label}
|
|
463
|
+
handleSelectedItems={value => changeFilterActive(outerIndex, value)}
|
|
464
|
+
/>
|
|
465
|
+
)}
|
|
466
|
+
{showDefaultDropdown && (
|
|
467
|
+
<Dropdown
|
|
468
|
+
filter={singleFilter}
|
|
469
|
+
index={outerIndex}
|
|
470
|
+
label={label}
|
|
471
|
+
active={queuedActive || active}
|
|
472
|
+
filters={DropdownOptions}
|
|
473
|
+
/>
|
|
474
|
+
)}
|
|
475
|
+
</>
|
|
476
|
+
</div>
|
|
477
|
+
)
|
|
478
|
+
})
|
|
450
479
|
}
|
|
451
480
|
|
|
452
481
|
if (visualizationConfig?.filters?.length === 0) return
|
|
482
|
+
const filterSectionClassList = [
|
|
483
|
+
`filters-section legend_${visualizationConfig?.legend?.hide ? 'hidden' : 'visible'}_${
|
|
484
|
+
visualizationConfig?.legend?.position || ''
|
|
485
|
+
}`,
|
|
486
|
+
type === 'map' ? general.headerColor : visualizationConfig?.visualizationType === 'Spark Line' ? null : theme
|
|
487
|
+
]
|
|
453
488
|
return (
|
|
454
|
-
<
|
|
455
|
-
<
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
</
|
|
459
|
-
|
|
489
|
+
<section className={filterSectionClassList.join(' ')}>
|
|
490
|
+
<p className='filters-section__intro-text'>
|
|
491
|
+
{filters?.some(f => f.active && f.showDropdown) ? filterConstants.introText : ''}{' '}
|
|
492
|
+
{visualizationConfig.filterBehavior === 'Apply Button' && filterConstants.applyText}
|
|
493
|
+
</p>
|
|
494
|
+
<div className='filters-section__wrapper'>
|
|
495
|
+
{' '}
|
|
496
|
+
<>
|
|
497
|
+
<Style />
|
|
498
|
+
{filterBehavior === 'Apply Button' ? (
|
|
499
|
+
<div className='filters-section__buttons'>
|
|
500
|
+
<Button
|
|
501
|
+
onClick={() => handleApplyButton(filters)}
|
|
502
|
+
disabled={!showApplyButton}
|
|
503
|
+
className={[general?.headerColor ? general.headerColor : theme, 'apply'].join(' ')}
|
|
504
|
+
>
|
|
505
|
+
{filterConstants.buttonText}
|
|
506
|
+
</Button>
|
|
507
|
+
<a href='#!' role='button' onClick={handleReset}>
|
|
508
|
+
{filterConstants.resetText}
|
|
509
|
+
</a>
|
|
510
|
+
</div>
|
|
511
|
+
) : (
|
|
512
|
+
<></>
|
|
513
|
+
)}
|
|
514
|
+
</>
|
|
515
|
+
</div>
|
|
516
|
+
</section>
|
|
460
517
|
)
|
|
461
518
|
}
|
|
462
519
|
|
|
463
|
-
Filters.propTypes = {
|
|
464
|
-
// runtimeFilters in place
|
|
465
|
-
filteredData: PropTypes.array,
|
|
466
|
-
// function for updating the runtime filters
|
|
467
|
-
setFilteredData: PropTypes.func,
|
|
468
|
-
// the full apps config
|
|
469
|
-
config: PropTypes.object,
|
|
470
|
-
// updating function for setting fitlerBehavior
|
|
471
|
-
setConfig: PropTypes.func,
|
|
472
|
-
// exclusions
|
|
473
|
-
excludedData: PropTypes.array,
|
|
474
|
-
dimensions: PropTypes.array
|
|
475
|
-
}
|
|
476
|
-
|
|
477
520
|
export default Filters
|