@cdc/dashboard 4.25.10 → 4.26.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/Dynamic_Data.md +66 -0
- package/dist/{cdcdashboard-fce76882.es.js → cdcdashboard-BnB1QM5d.es.js} +6 -13
- package/dist/{cdcdashboard-c55ac1ea.es.js → cdcdashboard-D6CG2-Hb.es.js} +5 -12
- package/dist/{cdcdashboard-31a33da1.es.js → cdcdashboard-MXgURbdZ.es.js} +6 -13
- package/dist/{cdcdashboard-1a1724a1.es.js → cdcdashboard-dgT_1dIT.es.js} +136 -151
- package/dist/cdcdashboard.js +84214 -79641
- package/examples/api-dashboard-data.json +272 -0
- package/examples/api-dashboard-years.json +11 -0
- package/examples/api-geographies-data.json +11 -0
- package/examples/api-test/categories.json +18 -0
- package/examples/api-test/chart-data.json +602 -0
- package/examples/api-test/topics.json +47 -0
- package/examples/api-test/years.json +22 -0
- package/examples/markup-axis-label.json +4167 -0
- package/examples/private/big-dashboard.json +39095 -39077
- package/examples/private/cat-y.json +1235 -0
- package/examples/private/chronic-dash.json +1584 -0
- package/examples/private/clade-2.json +430 -0
- package/examples/private/diabetes.json +546 -196
- package/examples/private/map-issue.json +2260 -0
- package/examples/private/markup-footer/mortality-deaths-footnotes-age.csv +3 -0
- package/examples/private/mpinc-state-reports.json +2260 -0
- package/examples/private/mpox.json +38128 -0
- package/examples/private/nwss/rsv.json +1240 -0
- package/examples/private/reset.json +32920 -0
- package/examples/private/simple-dash.json +490 -0
- package/examples/private/test-dash.json +0 -0
- package/examples/private/test123.json +491 -0
- package/examples/test-api-filter-reset.json +132 -0
- package/examples/test-dashboard-simple.json +503 -0
- package/index.html +25 -26
- package/package.json +11 -11
- package/src/CdcDashboardComponent.tsx +35 -10
- package/src/DashboardContext.tsx +3 -1
- package/src/_stories/Dashboard.DataSetup.stories.tsx +203 -0
- package/src/_stories/Dashboard.stories.tsx +402 -1
- package/src/_stories/_mock/custom-order-new-values.json +116 -0
- package/src/_stories/_mock/filter-cascade.json +3350 -0
- package/src/_stories/_mock/gallery-data-bite-dashboard.json +3500 -0
- package/src/_stories/_mock/nested-parent-child-filters.json +392 -0
- package/src/_stories/_mock/parent-child-filters.json +233 -0
- package/src/components/DashboardFilters/DashboardFilters.tsx +54 -31
- package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +118 -50
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +96 -108
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/NestedDropDownDashboard.tsx +196 -59
- package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +129 -29
- package/src/components/DashboardFilters/_stories/DashboardFilters.stories.tsx +62 -3
- package/src/components/DataDesignerModal.tsx +18 -6
- package/src/components/Header/Header.tsx +53 -21
- package/src/components/Toggle/Toggle.tsx +48 -48
- package/src/components/VisualizationRow.tsx +73 -6
- package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +2 -3
- package/src/components/Widget/Widget.tsx +1 -1
- package/src/data/initial-state.js +1 -0
- package/src/helpers/addValuesToDashboardFilters.ts +24 -6
- package/src/helpers/apiFilterHelpers.ts +26 -2
- package/src/helpers/changeFilterActive.ts +67 -65
- package/src/helpers/filterData.ts +52 -7
- package/src/helpers/filterResetHelpers.ts +102 -0
- package/src/helpers/formatConfigBeforeSave.ts +6 -5
- package/src/helpers/getUpdateConfig.ts +91 -91
- package/src/helpers/getVizConfig.ts +2 -2
- package/src/helpers/loadAPIFilters.ts +109 -99
- package/src/helpers/tests/filterResetHelpers.test.ts +532 -0
- package/src/helpers/tests/updatesChildFilters.test.ts +53 -22
- package/src/helpers/updateChildFilters.ts +50 -27
- package/src/index.tsx +1 -0
- package/src/scss/editor-panel.scss +3 -431
- package/src/scss/main.scss +142 -25
- package/src/store/errorMessage/errorMessage.reducer.ts +1 -1
- package/src/test/CdcDashboard.test.jsx +9 -4
- package/src/types/Dashboard.ts +1 -0
- package/src/types/DashboardFilters.ts +9 -8
- package/src/types/FilterStyles.ts +8 -7
- package/src/types/SharedFilter.ts +13 -0
- package/LICENSE +0 -201
- package/examples/private/DEV-11072.json +0 -7591
- package/examples/private/burden_toolkit_mortality_diabetes_attributable_deaths_data.csv +0 -14041
- package/examples/private/burden_toolkit_mortality_diabetes_attributable_deaths_per_100000_data.csv +0 -14041
- package/examples/private/burden_toolkit_mortality_qaly_data.csv +0 -18721
- package/examples/private/burden_toolkit_mortality_yll_data.csv +0 -18721
- package/examples/private/pedro.json +0 -1
- package/src/helpers/getAutoLoadVisualization.ts +0 -11
- package/src/scss/mixins.scss +0 -47
- package/src/scss/variables.scss +0 -5
- /package/dist/{cdcdashboard-548642e6.es.js → cdcdashboard-Ct2SB0vL.es.js} +0 -0
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import MultiSelect from '@cdc/core/components/MultiSelect'
|
|
3
|
+
import ComboBox from '@cdc/core/components/ComboBox'
|
|
3
4
|
import { SharedFilter } from '../../types/SharedFilter'
|
|
4
5
|
import { APIFilterDropdowns, DropdownOptions } from './DashboardFiltersWrapper'
|
|
5
6
|
import { FILTER_STYLE } from '../../types/FilterStyles'
|
|
6
7
|
import { NestedOptions, ValueTextPair } from '@cdc/core/components/NestedDropdown/nestedDropdownHelpers'
|
|
7
8
|
import NestedDropdown from '@cdc/core/components/NestedDropdown'
|
|
9
|
+
import { getNestedOptions } from '@cdc/core/components/Filters/helpers/getNestedOptions'
|
|
8
10
|
import { MouseEventHandler } from 'react'
|
|
9
11
|
import Loader from '@cdc/core/components/Loader'
|
|
10
12
|
import _ from 'lodash'
|
|
@@ -18,6 +20,7 @@ type DashboardFilterProps = {
|
|
|
18
20
|
showSubmit: boolean
|
|
19
21
|
applyFilters: MouseEventHandler<HTMLButtonElement>
|
|
20
22
|
applyFiltersButtonText?: string
|
|
23
|
+
handleReset?: MouseEventHandler<HTMLButtonElement>
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
const DashboardFilters: React.FC<DashboardFilterProps> = ({
|
|
@@ -27,7 +30,8 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
|
|
|
27
30
|
handleOnChange,
|
|
28
31
|
showSubmit,
|
|
29
32
|
applyFilters,
|
|
30
|
-
applyFiltersButtonText
|
|
33
|
+
applyFiltersButtonText,
|
|
34
|
+
handleReset
|
|
31
35
|
}) => {
|
|
32
36
|
const nullVal = (filter: SharedFilter) => {
|
|
33
37
|
const val = filter.queuedActive || filter.active
|
|
@@ -54,14 +58,12 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
|
|
|
54
58
|
|
|
55
59
|
return (
|
|
56
60
|
<form className='d-flex flex-wrap'>
|
|
57
|
-
{
|
|
61
|
+
{show.map(filterIndex => {
|
|
62
|
+
const filter = sharedFilters[filterIndex]
|
|
58
63
|
const urlFilterType = filter.type === 'urlfilter'
|
|
59
64
|
const label = stripDuplicateLabelIncrement(filter.key || '')
|
|
60
65
|
|
|
61
|
-
if (
|
|
62
|
-
(!urlFilterType && !filter.showDropdown && filter.filterStyle !== FILTER_STYLE.nestedDropdown) ||
|
|
63
|
-
(show && !show.includes(filterIndex))
|
|
64
|
-
)
|
|
66
|
+
if (!urlFilterType && !filter.showDropdown && filter.filterStyle !== FILTER_STYLE.nestedDropdown)
|
|
65
67
|
return <React.Fragment key={`${filter.key}-filtersection-${filterIndex}-option`} />
|
|
66
68
|
const values: JSX.Element[] = []
|
|
67
69
|
|
|
@@ -69,12 +71,11 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
|
|
|
69
71
|
const loading = apiFilterDropdowns[_key] === null
|
|
70
72
|
|
|
71
73
|
const multiValues: { value; label }[] = []
|
|
72
|
-
const nestedOptions: NestedOptions =
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)
|
|
74
|
+
const nestedOptions: NestedOptions = getNestedOptions({
|
|
75
|
+
orderedValues: filter.orderedValues,
|
|
76
|
+
values: filter.values,
|
|
77
|
+
subGrouping: filter.subGrouping
|
|
78
|
+
})
|
|
78
79
|
|
|
79
80
|
if (_key && apiFilterDropdowns[_key]) {
|
|
80
81
|
// URL Filter
|
|
@@ -115,8 +116,8 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
|
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
const isDisabled = !values.length
|
|
118
|
-
// push reset label only if it does not includes in filter values
|
|
119
|
-
if (filter.resetLabel && !filter.values.includes(filter.resetLabel)) {
|
|
119
|
+
// push reset label only if it does not includes in filter values options
|
|
120
|
+
if (filter.resetLabel && !filter.values.includes(filter.resetLabel) && !_key) {
|
|
120
121
|
values.unshift(
|
|
121
122
|
<option key={`${filter.resetLabel}-option`} value={filter.resetLabel}>
|
|
122
123
|
{filter.resetLabel}
|
|
@@ -145,15 +146,23 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
|
|
|
145
146
|
) : filter.filterStyle === FILTER_STYLE.nestedDropdown ? (
|
|
146
147
|
<NestedDropdown
|
|
147
148
|
activeGroup={(filter.queuedActive?.[0] || filter.active) as string}
|
|
148
|
-
activeSubGroup={
|
|
149
|
-
_key ? filter.queuedActive?.[1] || filter.subGrouping?.active : filter.subGrouping?.active
|
|
150
|
-
}
|
|
149
|
+
activeSubGroup={(filter.queuedActive?.[1] || filter.subGrouping?.active) as string}
|
|
151
150
|
filterIndex={filterIndex}
|
|
152
151
|
options={_key ? getNestedDropdownOptions(apiFilterDropdowns[_key]) : nestedOptions}
|
|
153
152
|
listLabel={label}
|
|
154
153
|
handleSelectedItems={value => updateField(null, null, filterIndex, value)}
|
|
155
154
|
loading={loading}
|
|
156
155
|
/>
|
|
156
|
+
) : filter.filterStyle === FILTER_STYLE.combobox ? (
|
|
157
|
+
<ComboBox
|
|
158
|
+
options={multiValues}
|
|
159
|
+
fieldName={filterIndex}
|
|
160
|
+
updateField={updateField}
|
|
161
|
+
selected={(filter.queuedActive || filter.active) as string}
|
|
162
|
+
label={label}
|
|
163
|
+
loading={loading}
|
|
164
|
+
placeholder={filter.resetLabel || '- Select -'}
|
|
165
|
+
/>
|
|
157
166
|
) : (
|
|
158
167
|
<>
|
|
159
168
|
<select
|
|
@@ -167,7 +176,14 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
|
|
|
167
176
|
disabled={loading || isDisabled}
|
|
168
177
|
>
|
|
169
178
|
{loading && <option value='Loading...'>Loading...</option>}
|
|
170
|
-
{
|
|
179
|
+
{/* For API filters, show placeholder when no value is selected */}
|
|
180
|
+
{_key && nullVal(filter) && (
|
|
181
|
+
<option key={`reset-label`} value=''>
|
|
182
|
+
{filter.resetLabel || '- Select One -'}
|
|
183
|
+
</option>
|
|
184
|
+
)}
|
|
185
|
+
{/* For non-API filters or when no value is selected, show empty option */}
|
|
186
|
+
{!_key && nullVal(filter) && (
|
|
171
187
|
<option key={`select`} value=''>
|
|
172
188
|
{filter.resetLabel || '- Select -'}
|
|
173
189
|
</option>
|
|
@@ -181,19 +197,26 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
|
|
|
181
197
|
)
|
|
182
198
|
})}
|
|
183
199
|
{showSubmit && (
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
200
|
+
<>
|
|
201
|
+
<button
|
|
202
|
+
className='btn btn-primary mb-1 me-2'
|
|
203
|
+
onClick={applyFilters}
|
|
204
|
+
disabled={show.some(filterIndex => {
|
|
205
|
+
const emptyFilterValues = [undefined, '', '- Select -']
|
|
206
|
+
return (
|
|
207
|
+
emptyFilterValues.includes(sharedFilters[filterIndex].queuedActive) &&
|
|
208
|
+
emptyFilterValues.includes(sharedFilters[filterIndex].active)
|
|
209
|
+
)
|
|
210
|
+
})}
|
|
211
|
+
>
|
|
212
|
+
{applyFiltersButtonText || 'GO!'}
|
|
213
|
+
</button>
|
|
214
|
+
{handleReset && (
|
|
215
|
+
<button className='btn btn-link mb-1' onClick={handleReset}>
|
|
216
|
+
Clear Filters
|
|
217
|
+
</button>
|
|
218
|
+
)}
|
|
219
|
+
</>
|
|
197
220
|
)}
|
|
198
221
|
</form>
|
|
199
222
|
)
|
|
@@ -21,6 +21,7 @@ import { addValuesToDashboardFilters } from '../../../helpers/addValuesToDashboa
|
|
|
21
21
|
import { FILTER_STYLE } from '../../../types/FilterStyles'
|
|
22
22
|
import { handleSorting } from '@cdc/core/components/Filters'
|
|
23
23
|
import { removeDashboardFilter } from '../../../helpers/removeDashboardFilter'
|
|
24
|
+
import { DragDropContext, Droppable, Draggable, DropResult } from '@hello-pangea/dnd'
|
|
24
25
|
|
|
25
26
|
type DashboardFitlersEditorProps = {
|
|
26
27
|
vizConfig: DashboardFilters
|
|
@@ -43,9 +44,10 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
|
|
|
43
44
|
return config.dashboard.sharedFilters
|
|
44
45
|
?.map<[number, string]>(({ key }, i) => [i, key])
|
|
45
46
|
.filter(([filterIndex]) => !sharedFilterIndexes.includes(filterIndex)) // filter out already added filters
|
|
46
|
-
.map(([filterIndex, filterName]) => (
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
.map(([filterIndex, filterName]) => ({
|
|
48
|
+
value: String(filterIndex),
|
|
49
|
+
label: `${filterIndex} - ${filterName}`
|
|
50
|
+
}))
|
|
49
51
|
}, [config.visualizations, vizConfig.uid])
|
|
50
52
|
|
|
51
53
|
const openControls = useState({})
|
|
@@ -70,6 +72,7 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
|
|
|
70
72
|
newSharedFilters[index][prop] = value
|
|
71
73
|
if (prop === 'columnName') {
|
|
72
74
|
if (newSharedFilters[index].subGrouping) delete newSharedFilters[index].subGrouping
|
|
75
|
+
newSharedFilters[index].defaultValue = ''
|
|
73
76
|
// changing a data column and want to load the data into the preview options
|
|
74
77
|
const sharedFiltersWithValues = addValuesToDashboardFilters(newSharedFilters, data)
|
|
75
78
|
dispatch({ type: 'SET_SHARED_FILTERS', payload: sharedFiltersWithValues })
|
|
@@ -121,6 +124,29 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
|
|
|
121
124
|
dispatch({ type: 'SET_CONFIG', payload: { dashboard, visualizations: newVisualizations } })
|
|
122
125
|
}
|
|
123
126
|
|
|
127
|
+
const handleFilterReorder = (result: DropResult) => {
|
|
128
|
+
const { source, destination } = result
|
|
129
|
+
if (!destination || source.index === destination.index) return
|
|
130
|
+
|
|
131
|
+
const newIndexes = [...vizConfig.sharedFilterIndexes]
|
|
132
|
+
const [movedIndex] = newIndexes.splice(source.index, 1)
|
|
133
|
+
newIndexes.splice(destination.index, 0, movedIndex)
|
|
134
|
+
|
|
135
|
+
updateConfig({
|
|
136
|
+
...vizConfig,
|
|
137
|
+
sharedFilterIndexes: newIndexes
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const getItemStyle = (isDragging, draggableStyle) => ({
|
|
142
|
+
...draggableStyle,
|
|
143
|
+
...(isDragging && sortableItemStyles)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
const sortableItemStyles = {
|
|
147
|
+
background: 'rgba(0, 0, 0, 0.1)'
|
|
148
|
+
}
|
|
149
|
+
|
|
124
150
|
const addNewFilter = () => {
|
|
125
151
|
const _sharedFilters = _.cloneDeep(sharedFilters) || []
|
|
126
152
|
const columnName = 'New Dashboard Filter ' + (_sharedFilters.length + 1)
|
|
@@ -189,6 +215,27 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
|
|
|
189
215
|
}
|
|
190
216
|
/>
|
|
191
217
|
)}
|
|
218
|
+
{vizConfig.filterBehavior === 'Apply Button' && (
|
|
219
|
+
<CheckBox
|
|
220
|
+
label='Show Clear Filters Button'
|
|
221
|
+
value={vizConfig.showClearButton ?? true}
|
|
222
|
+
updateField={(_section, _subsection, _key, value) => {
|
|
223
|
+
updateConfig({ ...vizConfig, showClearButton: value })
|
|
224
|
+
}}
|
|
225
|
+
tooltip={
|
|
226
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
227
|
+
<Tooltip.Target>
|
|
228
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
229
|
+
</Tooltip.Target>
|
|
230
|
+
<Tooltip.Content>
|
|
231
|
+
<p>
|
|
232
|
+
When enabled, displays a "Clear Filters" button that allows users to reset all filter selections.
|
|
233
|
+
</p>
|
|
234
|
+
</Tooltip.Content>
|
|
235
|
+
</Tooltip>
|
|
236
|
+
}
|
|
237
|
+
/>
|
|
238
|
+
)}
|
|
192
239
|
</AccordionItemPanel>
|
|
193
240
|
</AccordionItem>
|
|
194
241
|
|
|
@@ -197,44 +244,70 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
|
|
|
197
244
|
<AccordionItemButton>Filters</AccordionItemButton>
|
|
198
245
|
</AccordionItemHeading>
|
|
199
246
|
<AccordionItemPanel>
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
247
|
+
<DragDropContext onDragEnd={handleFilterReorder}>
|
|
248
|
+
<Droppable droppableId='dashboard_filters_list'>
|
|
249
|
+
{provided => (
|
|
250
|
+
<ul {...provided.droppableProps} ref={provided.innerRef} className='draggable-field-list'>
|
|
251
|
+
{vizConfig.sharedFilterIndexes.map((index, filterIndex) => {
|
|
252
|
+
const filter = sharedFilters[index]
|
|
253
|
+
return (
|
|
254
|
+
<Draggable
|
|
255
|
+
key={filter.key + index}
|
|
256
|
+
draggableId={`filter-${filter.key}-${index}`}
|
|
257
|
+
index={filterIndex}
|
|
258
|
+
>
|
|
259
|
+
{(provided, snapshot) => (
|
|
260
|
+
<div
|
|
261
|
+
ref={provided.innerRef}
|
|
262
|
+
{...provided.draggableProps}
|
|
263
|
+
{...provided.dragHandleProps}
|
|
264
|
+
style={getItemStyle(snapshot.isDragging, provided.draggableProps.style)}
|
|
265
|
+
className={snapshot.isDragging ? 'currently-dragging' : ''}
|
|
266
|
+
>
|
|
267
|
+
<FieldSetWrapper
|
|
268
|
+
key={filter.key + index}
|
|
269
|
+
fieldName={filter.key}
|
|
270
|
+
fieldKey={index}
|
|
271
|
+
fieldType='Dashboard Filter'
|
|
272
|
+
controls={openControls}
|
|
273
|
+
draggable={true}
|
|
274
|
+
deleteField={() => {
|
|
275
|
+
overlay?.actions.openOverlay(
|
|
276
|
+
<DeleteFilterModal
|
|
277
|
+
removeFilterCompletely={removeFilter}
|
|
278
|
+
removeFilterFromViz={index => {
|
|
279
|
+
updateConfig({
|
|
280
|
+
...vizConfig,
|
|
281
|
+
sharedFilterIndexes: vizConfig.sharedFilterIndexes.filter(i => i !== index)
|
|
282
|
+
})
|
|
283
|
+
}}
|
|
284
|
+
filterIndex={index}
|
|
285
|
+
/>
|
|
286
|
+
)
|
|
287
|
+
}}
|
|
288
|
+
>
|
|
289
|
+
<FilterEditor
|
|
290
|
+
filter={filter}
|
|
291
|
+
filterIndex={index}
|
|
292
|
+
updateFilterProp={(name, value) => {
|
|
293
|
+
updateFilterProp(name, index, value)
|
|
294
|
+
}}
|
|
295
|
+
toggleNestedQueryParameters={checked => {
|
|
296
|
+
toggleNestedQueryParameters(index, checked)
|
|
297
|
+
}}
|
|
298
|
+
config={config}
|
|
299
|
+
/>
|
|
300
|
+
</FieldSetWrapper>
|
|
301
|
+
</div>
|
|
302
|
+
)}
|
|
303
|
+
</Draggable>
|
|
304
|
+
)
|
|
305
|
+
})}
|
|
306
|
+
{provided.placeholder}
|
|
307
|
+
</ul>
|
|
308
|
+
)}
|
|
309
|
+
</Droppable>
|
|
310
|
+
</DragDropContext>
|
|
238
311
|
<button onClick={addNewFilter} className='btn btn-primary full-width'>
|
|
239
312
|
Add Filter
|
|
240
313
|
</button>
|
|
@@ -254,8 +327,10 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
|
|
|
254
327
|
</Tooltip.Content>
|
|
255
328
|
</Tooltip>
|
|
256
329
|
</span>
|
|
257
|
-
<
|
|
330
|
+
<Select
|
|
331
|
+
label=''
|
|
258
332
|
value={''}
|
|
333
|
+
options={[{ value: '', label: 'Select' }, ...(existingOptions || [])]}
|
|
259
334
|
onChange={e => {
|
|
260
335
|
updateConfig({
|
|
261
336
|
...vizConfig,
|
|
@@ -263,14 +338,7 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
|
|
|
263
338
|
})
|
|
264
339
|
setCanAddExisting(false)
|
|
265
340
|
}}
|
|
266
|
-
|
|
267
|
-
{[
|
|
268
|
-
<option key='select' value=''>
|
|
269
|
-
Select
|
|
270
|
-
</option>,
|
|
271
|
-
...existingOptions
|
|
272
|
-
]}
|
|
273
|
-
</select>
|
|
341
|
+
/>
|
|
274
342
|
</label>
|
|
275
343
|
) : (
|
|
276
344
|
<button onClick={() => setCanAddExisting(true)} className='btn btn-primary full-width mt-2'>
|
|
@@ -43,7 +43,11 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
|
|
|
43
43
|
const filterStyles = Object.values(FILTER_STYLE)
|
|
44
44
|
|
|
45
45
|
const parentFilters: string[] = (config.dashboard.sharedFilters || [])
|
|
46
|
-
.filter(({ key
|
|
46
|
+
.filter(({ key }) => key !== filter.key)
|
|
47
|
+
.map(({ key }) => key)
|
|
48
|
+
|
|
49
|
+
const dataFilterParents: string[] = (config.dashboard.sharedFilters || [])
|
|
50
|
+
.filter(({ key }) => key !== filter.key)
|
|
47
51
|
.map(({ key }) => key)
|
|
48
52
|
|
|
49
53
|
const vizRowColumnLocator = getVizRowColumnLocator(config.rows)
|
|
@@ -184,33 +188,25 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
|
|
|
184
188
|
return (
|
|
185
189
|
<>
|
|
186
190
|
{dataFiltersLoading && <Loading />}
|
|
187
|
-
<
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
</label>
|
|
191
|
+
<Select
|
|
192
|
+
label='Filter Type'
|
|
193
|
+
value={filter.type || ''}
|
|
194
|
+
options={[
|
|
195
|
+
{ value: '', label: '- Select Option -' },
|
|
196
|
+
{ value: 'urlfilter', label: 'URL' },
|
|
197
|
+
{ value: 'datafilter', label: 'Data' }
|
|
198
|
+
]}
|
|
199
|
+
onChange={e => selectFilterType(e.target.value)}
|
|
200
|
+
disabled={!!filter.type}
|
|
201
|
+
/>
|
|
199
202
|
{filter.type !== undefined && (
|
|
200
203
|
<>
|
|
201
|
-
<
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
{filterStyles.map(dataKey => (
|
|
208
|
-
<option value={dataKey} key={`filter-style-select-item-${dataKey}`}>
|
|
209
|
-
{dataKey}
|
|
210
|
-
</option>
|
|
211
|
-
))}
|
|
212
|
-
</select>
|
|
213
|
-
</label>
|
|
204
|
+
<Select
|
|
205
|
+
label='Filter Style'
|
|
206
|
+
value={filter.filterStyle || FILTER_STYLE.dropdown}
|
|
207
|
+
options={filterStyles}
|
|
208
|
+
onChange={e => updateFilterProp('filterStyle', e.target.value)}
|
|
209
|
+
/>
|
|
214
210
|
{filter.filterStyle === FILTER_STYLE.dropdown && (
|
|
215
211
|
<label>
|
|
216
212
|
<span className='me-1'>Show Dropdown</span>
|
|
@@ -254,41 +250,50 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
|
|
|
254
250
|
<>
|
|
255
251
|
{!hasDashboardApplyBehavior(config.visualizations) && (
|
|
256
252
|
<>
|
|
257
|
-
<
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
253
|
+
<Select
|
|
254
|
+
label='Filter By'
|
|
255
|
+
value={filter.filterBy || ''}
|
|
256
|
+
options={[
|
|
257
|
+
{ value: '', label: '- Select Option -' },
|
|
258
|
+
{ value: 'Query String', label: 'Query String' },
|
|
259
|
+
{ value: 'File Name', label: 'File Name' }
|
|
260
|
+
]}
|
|
261
|
+
onChange={e => updateFilterProp('filterBy', e.target.value)}
|
|
262
|
+
/>
|
|
263
|
+
|
|
264
|
+
{filter.filterBy === 'File Name' && (
|
|
265
|
+
<Select
|
|
266
|
+
label='URL to Filter'
|
|
267
|
+
value={filter.datasetKey || ''}
|
|
268
|
+
options={[
|
|
269
|
+
{ value: '', label: '- Select Option -' },
|
|
270
|
+
...Object.keys(config.datasets)
|
|
271
|
+
.filter(datasetKey => config.datasets[datasetKey].dataUrl)
|
|
272
|
+
.map(datasetKey => ({
|
|
273
|
+
value: datasetKey,
|
|
274
|
+
label: config.datasets[datasetKey].dataUrl
|
|
275
|
+
}))
|
|
276
|
+
]}
|
|
261
277
|
onChange={e => updateFilterProp('datasetKey', e.target.value)}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
</select>
|
|
275
|
-
</label>
|
|
278
|
+
tooltip={
|
|
279
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
280
|
+
<Tooltip.Target>
|
|
281
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
282
|
+
</Tooltip.Target>
|
|
283
|
+
<Tooltip.Content>
|
|
284
|
+
<p>Select which dataset URL's filename should be modified by this filter.</p>
|
|
285
|
+
</Tooltip.Content>
|
|
286
|
+
</Tooltip>
|
|
287
|
+
}
|
|
288
|
+
/>
|
|
289
|
+
)}
|
|
276
290
|
|
|
277
|
-
|
|
278
|
-
<
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
<option value=''>- Select Option -</option>
|
|
284
|
-
<option key={'query-string'} value={'Query String'}>
|
|
285
|
-
Query String
|
|
286
|
-
</option>
|
|
287
|
-
<option key={'file-name'} value={'File Name'}>
|
|
288
|
-
File Name
|
|
289
|
-
</option>
|
|
290
|
-
</select>
|
|
291
|
-
</label>
|
|
291
|
+
{filter.filterBy === 'Query String' && filter.usedBy && filter.usedBy.length > 0 && (
|
|
292
|
+
<div className='bg-info-subtle p-2 my-2' style={{ fontSize: '0.9em' }}>
|
|
293
|
+
<Icon display='info' style={{ marginRight: '0.5rem' }} />
|
|
294
|
+
Will apply to datasets used by selected widgets
|
|
295
|
+
</div>
|
|
296
|
+
)}
|
|
292
297
|
{filter.filterBy === 'File Name' && (
|
|
293
298
|
<>
|
|
294
299
|
<TextField
|
|
@@ -307,9 +312,16 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
|
|
|
307
312
|
}
|
|
308
313
|
/>
|
|
309
314
|
|
|
310
|
-
<
|
|
311
|
-
|
|
312
|
-
|
|
315
|
+
<Select
|
|
316
|
+
label='White Space Replacments'
|
|
317
|
+
value={filter.whitespaceReplacement || 'Keep Spaces'}
|
|
318
|
+
options={[
|
|
319
|
+
{ value: 'Remove Spaces', label: 'Remove Spaces' },
|
|
320
|
+
{ value: 'Replace With Underscore', label: 'Replace With Underscore' },
|
|
321
|
+
{ value: 'Keep Spaces', label: 'Keep Spaces' }
|
|
322
|
+
]}
|
|
323
|
+
onChange={e => updateFilterProp('whitespaceReplacement', e.target.value)}
|
|
324
|
+
tooltip={
|
|
313
325
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
314
326
|
<Tooltip.Target>
|
|
315
327
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
@@ -318,22 +330,8 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
|
|
|
318
330
|
<p>{`Set how whitespace characters will be handled in the file request`}</p>
|
|
319
331
|
</Tooltip.Content>
|
|
320
332
|
</Tooltip>
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
defaultValue={filter.whitespaceReplacement || 'Keep Spaces'}
|
|
324
|
-
onChange={e => updateFilterProp('whitespaceReplacement', e.target.value)}
|
|
325
|
-
>
|
|
326
|
-
<option key={'remove-spaces'} value={'Remove Spaces'}>
|
|
327
|
-
Remove Spaces
|
|
328
|
-
</option>
|
|
329
|
-
<option key={'replace-with-underscore'} value={'Replace With Underscore'}>
|
|
330
|
-
Replace With Underscore
|
|
331
|
-
</option>
|
|
332
|
-
<option key={'keep-spaces'} value={'Keep Spaces'}>
|
|
333
|
-
Keep Spaces
|
|
334
|
-
</option>
|
|
335
|
-
</select>
|
|
336
|
-
</label>
|
|
333
|
+
}
|
|
334
|
+
/>
|
|
337
335
|
</>
|
|
338
336
|
)}
|
|
339
337
|
</>
|
|
@@ -507,22 +505,17 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
|
|
|
507
505
|
<>
|
|
508
506
|
{filter.filterStyle !== FILTER_STYLE.nestedDropdown ? (
|
|
509
507
|
<>
|
|
510
|
-
<
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
{dataKey}
|
|
522
|
-
</option>
|
|
523
|
-
))}
|
|
524
|
-
</select>
|
|
525
|
-
</label>
|
|
508
|
+
<Select
|
|
509
|
+
label='Filter'
|
|
510
|
+
value={filter.columnName || ''}
|
|
511
|
+
options={[
|
|
512
|
+
{ value: '', label: '- Select Option -' },
|
|
513
|
+
...columns.map(col => ({ value: col, label: col }))
|
|
514
|
+
]}
|
|
515
|
+
onChange={e => {
|
|
516
|
+
updateFilterProp('columnName', e.target.value)
|
|
517
|
+
}}
|
|
518
|
+
/>
|
|
526
519
|
|
|
527
520
|
<Select
|
|
528
521
|
value={filter.defaultValue}
|
|
@@ -648,21 +641,16 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
|
|
|
648
641
|
/>
|
|
649
642
|
|
|
650
643
|
<label>
|
|
651
|
-
<span className='edit-label column-heading'>Parent Filter: </span>
|
|
652
|
-
<
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
644
|
+
<span className='edit-label column-heading mt-1'>Parent Filter(s): </span>
|
|
645
|
+
<MultiSelect
|
|
646
|
+
label='Parent Filter(s): '
|
|
647
|
+
options={dataFilterParents.map(key => ({ value: key, label: key }))}
|
|
648
|
+
fieldName='parents'
|
|
649
|
+
selected={filter.parents}
|
|
650
|
+
updateField={(_section, _subsection, _fieldname, newItems) => {
|
|
651
|
+
updateFilterProp('parents', newItems)
|
|
656
652
|
}}
|
|
657
|
-
|
|
658
|
-
<option value=''>Select a filter</option>
|
|
659
|
-
{config.dashboard.sharedFilters &&
|
|
660
|
-
config.dashboard.sharedFilters.map(sharedFilter => {
|
|
661
|
-
if (sharedFilter.key !== filter.key) {
|
|
662
|
-
return <option key={sharedFilter.key}>{sharedFilter.key}</option>
|
|
663
|
-
}
|
|
664
|
-
})}
|
|
665
|
-
</select>
|
|
653
|
+
/>
|
|
666
654
|
</label>
|
|
667
655
|
|
|
668
656
|
{!isNestedDropdown && (
|