@cdc/dashboard 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.
Files changed (63) hide show
  1. package/Dynamic_Data.md +79 -0
  2. package/Override_Data.md +39 -0
  3. package/dist/cdcdashboard.js +76052 -77984
  4. package/examples/legend-issue-data.json +1874 -0
  5. package/examples/legend-issue.json +749 -0
  6. package/examples/map.json +628 -0
  7. package/examples/special-classes.json +54340 -0
  8. package/index.html +1 -26
  9. package/package.json +10 -15
  10. package/src/CdcDashboardComponent.tsx +65 -216
  11. package/src/_stories/Dashboard.stories.tsx +2 -0
  12. package/src/_stories/_mock/api-filter-map.json +43 -1
  13. package/src/components/CollapsibleVisualizationRow.tsx +4 -6
  14. package/src/components/DashboardEditors.tsx +143 -0
  15. package/src/components/DashboardFilters/DashboardFilters.tsx +205 -205
  16. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +286 -287
  17. package/src/components/DashboardFilters/DashboardFiltersEditor/components/APIModal.tsx +129 -0
  18. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +680 -652
  19. package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +198 -198
  20. package/src/components/DataDesignerModal.tsx +33 -14
  21. package/src/components/Header/Header.tsx +7 -9
  22. package/src/components/MultiConfigTabs/multiconfigtabs.styles.css +3 -0
  23. package/src/components/Row.tsx +2 -24
  24. package/src/components/VisualizationRow.tsx +191 -214
  25. package/src/helpers/getVizConfig.ts +93 -80
  26. package/src/helpers/getVizRowColumnLocator.ts +0 -1
  27. package/src/helpers/reloadURLHelpers.ts +11 -6
  28. package/src/helpers/shouldLoadAllFilters.ts +30 -30
  29. package/src/index.tsx +2 -1
  30. package/src/scss/main.scss +0 -5
  31. package/src/store/dashboard.actions.ts +61 -62
  32. package/src/store/dashboard.reducer.ts +15 -11
  33. package/src/types/ConfigRow.ts +0 -1
  34. package/src/types/Dashboard.ts +1 -1
  35. package/src/types/DashboardConfig.ts +1 -1
  36. package/src/types/SharedFilter.ts +2 -0
  37. package/examples/private/DEV-10120.json +0 -1294
  38. package/examples/private/DEV-10527.json +0 -845
  39. package/examples/private/DEV-10586.json +0 -54319
  40. package/examples/private/DEV-10856.json +0 -54319
  41. package/examples/private/DEV-9199.json +0 -606
  42. package/examples/private/DEV-9644.json +0 -20092
  43. package/examples/private/DEV-9684.json +0 -2135
  44. package/examples/private/DEV-9932.json +0 -95
  45. package/examples/private/DEV-9989.json +0 -229
  46. package/examples/private/art-dashboard.json +0 -18174
  47. package/examples/private/art-scratch.json +0 -2406
  48. package/examples/private/bird-flu-2.json +0 -440
  49. package/examples/private/bird-flu.json +0 -413
  50. package/examples/private/dashboard-config-ehdi.json +0 -29915
  51. package/examples/private/dashboard-map-filter.json +0 -815
  52. package/examples/private/dashboard-margins.js +0 -15
  53. package/examples/private/dataset.json +0 -1452
  54. package/examples/private/dev-10856-2.json +0 -1348
  55. package/examples/private/ehdi-data.json +0 -29502
  56. package/examples/private/exposure-source-h5-data.csv +0 -26
  57. package/examples/private/fatal-data.csv +0 -3159
  58. package/examples/private/feelings.json +0 -1
  59. package/examples/private/gaza-issue.json +0 -1214
  60. package/examples/private/markup.json +0 -115
  61. package/examples/private/nhis.json +0 -1792
  62. package/examples/private/workforce.json +0 -2041
  63. package/src/types/DataSet.ts +0 -11
@@ -1,287 +1,286 @@
1
- import {
2
- Accordion,
3
- AccordionItem,
4
- AccordionItemButton,
5
- AccordionItemHeading,
6
- AccordionItemPanel
7
- } from 'react-accessible-accordion'
8
- import { useContext, useMemo, useState } from 'react'
9
- import { CheckBox, Select, TextField } from '@cdc/core/components/EditorPanel/Inputs'
10
- import Tooltip from '@cdc/core/components/ui/Tooltip'
11
- import Icon from '@cdc/core/components/ui/Icon'
12
- import FieldSetWrapper from '@cdc/core/components/EditorPanel/FieldSetWrapper'
13
- import FilterEditor from './components/FilterEditor'
14
- import { AnyVisualization } from '@cdc/core/types/Visualization'
15
- import { DashboardContext, DashboardDispatchContext } from '../../../DashboardContext'
16
- import _ from 'lodash'
17
- import { DashboardFilters } from '../../../types/DashboardFilters'
18
- import { SharedFilter } from '../../../types/SharedFilter'
19
- import { useGlobalContext } from '@cdc/core/components/GlobalContext'
20
- import DeleteFilterModal from './components/DeleteFilterModal'
21
- import { addValuesToDashboardFilters } from '../../../helpers/addValuesToDashboardFilters'
22
- import { FILTER_STYLE } from '../../../types/FilterStyles'
23
- import { handleSorting } from '@cdc/core/components/Filters'
24
- import { removeDashboardFilter } from '../../../helpers/removeDashboardFilter'
25
-
26
- type DashboardFitlersEditorProps = {
27
- vizConfig: DashboardFilters
28
- updateConfig: Function
29
- }
30
-
31
- const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConfig, updateConfig }) => {
32
- const { config, loadAPIFilters, data } = useContext(DashboardContext)
33
- const { overlay } = useGlobalContext()
34
- const {
35
- dashboard: { sharedFilters },
36
- visualizations
37
- } = config
38
- const dispatch = useContext(DashboardDispatchContext)
39
-
40
- const existingOptions = useMemo(() => {
41
- const sharedFilterIndexes = (config.visualizations[vizConfig.uid] as DashboardFilters).sharedFilterIndexes.map(
42
- Number
43
- )
44
- return config.dashboard.sharedFilters
45
- ?.map<[number, string]>(({ key }, i) => [i, key])
46
- .filter(([filterIndex]) => !sharedFilterIndexes.includes(filterIndex)) // filter out already added filters
47
- .map(([filterIndex, filterName]) => (
48
- <option key={filterIndex} value={filterIndex}>{`${filterIndex} - ${filterName}`}</option>
49
- ))
50
- }, [config.visualizations, vizConfig.uid])
51
-
52
- const openControls = useState({})
53
- const [canAddExisting, setCanAddExisting] = useState(false)
54
-
55
- const updateFilterProp = (prop: string, index: number, value) => {
56
- const newSharedFilters = _.cloneDeep(sharedFilters)
57
- const {
58
- apiEndpoint: oldEndpoint,
59
- valueSelector: oldValueSelector,
60
- textSelector: oldTextSelector,
61
- subgroupValueSelector: oldSubgroupValueSelector,
62
- subgroupTextSelector: oldSubgroupTextSelector
63
- } = sharedFilters[index].apiFilter || {}
64
- const apiFilterChanged =
65
- value?.apiEndpoint !== oldEndpoint ||
66
- value?.valueSelector !== oldValueSelector ||
67
- value?.textSelector !== oldTextSelector ||
68
- value?.subgroupValueSelector !== oldSubgroupValueSelector ||
69
- value?.subgroupTextSelector !== oldSubgroupTextSelector
70
-
71
- newSharedFilters[index][prop] = value
72
- if (prop === 'columnName') {
73
- if (newSharedFilters[index].subGrouping) delete newSharedFilters[index].subGrouping
74
- // changing a data column and want to load the data into the preview options
75
- const sharedFiltersWithValues = addValuesToDashboardFilters(newSharedFilters, data)
76
- dispatch({ type: 'SET_SHARED_FILTERS', payload: sharedFiltersWithValues })
77
- } else if (prop === 'filterStyle') {
78
- newSharedFilters[index] = {
79
- ...newSharedFilters[index],
80
- active: '',
81
- apiFilter: {
82
- apiEndpoint: '',
83
- subgroupValueSelector: '',
84
- textSelector: '',
85
- valueSelector: ''
86
- },
87
- filterStyle: value
88
- }
89
- dispatch({ type: 'SET_SHARED_FILTERS', payload: newSharedFilters })
90
- } else if (prop === 'apiFilter' && value.apiEndpoint && value.valueSelector && apiFilterChanged) {
91
- if (sharedFilters[index].filterStyle === FILTER_STYLE.nestedDropdown && value.subgroupValueSelector) {
92
- newSharedFilters[index].subGrouping = {
93
- active: '',
94
- columnName: '',
95
- setByQueryParameter: '',
96
- valuesLookup: {}
97
- }
98
- }
99
- // changing a api filter and want to load the api data into the preview.
100
- // automatically dispatches SET_SHARED_FILTERS
101
- loadAPIFilters(newSharedFilters, {})
102
- } else {
103
- handleSorting(newSharedFilters[index])
104
- dispatch({ type: 'SET_SHARED_FILTERS', payload: newSharedFilters })
105
- }
106
- }
107
-
108
- const toggleNestedQueryParameters = (index, checked: boolean) => {
109
- const newSharedFilters = _.cloneDeep(sharedFilters)
110
- const filter = newSharedFilters[index]
111
- const isUrlFilter = filter.type === 'urlfilter'
112
- const groupColumnName = isUrlFilter ? filter.apiFilter.valueSelector : filter.columnName
113
- const subGroupColumnName = isUrlFilter ? filter.apiFilter.subgroupValueSelector : filter.subGrouping.columnName
114
- filter.setByQueryParameter = checked ? groupColumnName : undefined
115
- filter.subGrouping.setByQueryParameter = checked ? subGroupColumnName : undefined
116
- dispatch({ type: 'SET_SHARED_FILTERS', payload: newSharedFilters })
117
- }
118
-
119
- const removeFilter = index => {
120
- const [newSharedFilters, newVisualizations] = removeDashboardFilter(index, sharedFilters, visualizations)
121
- const dashboard = {...config.dashboard, sharedFilters: newSharedFilters}
122
- dispatch({ type: 'SET_CONFIG', payload: { dashboard, visualizations: newVisualizations } })
123
- }
124
-
125
- const addNewFilter = () => {
126
- const _sharedFilters = _.cloneDeep(sharedFilters) || []
127
- const columnName = 'New Dashboard Filter ' + (_sharedFilters.length + 1)
128
- const newFilter = { key: columnName, showDropdown: true, values: [] } as SharedFilter
129
- dispatch({ type: 'SET_SHARED_FILTERS', payload: [..._sharedFilters, newFilter] })
130
- updateConfig({ ...vizConfig, sharedFilterIndexes: [...vizConfig.sharedFilterIndexes, _sharedFilters.length] })
131
- }
132
-
133
- return (
134
- <Accordion allowZeroExpanded={true}>
135
- <AccordionItem>
136
- <AccordionItemHeading>
137
- <AccordionItemButton>General</AccordionItemButton>
138
- </AccordionItemHeading>
139
- <AccordionItemPanel>
140
- <Select
141
- value={vizConfig.filterBehavior}
142
- label='Filter Behavior'
143
- updateField={(_section, _subsection, _key, value) => {
144
- updateConfig({ ...vizConfig, filterBehavior: value })
145
- }}
146
- options={['Apply Button', 'Filter Change']}
147
- tooltip={
148
- <Tooltip style={{ textTransform: 'none' }}>
149
- <Tooltip.Target>
150
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
151
- </Tooltip.Target>
152
- <Tooltip.Content>
153
- <p>
154
- The Apply Button option changes the visualization when the user clicks "apply". The Filter Change
155
- option immediately changes the visualization when the selection is changed.
156
- </p>
157
- </Tooltip.Content>
158
- </Tooltip>
159
- }
160
- />
161
- {vizConfig.filterBehavior === 'Apply Button' && (
162
- <TextField
163
- label='Apply Filter Button Text'
164
- maxLength={20}
165
- value={vizConfig.applyFiltersButtonText}
166
- updateField={(_section, _subsection, _key, value) => {
167
- updateConfig({ ...vizConfig, applyFiltersButtonText: value })
168
- }}
169
- />
170
- )}
171
- {vizConfig.filterBehavior === 'Filter Change' && (
172
- <CheckBox
173
- label='Auto Load'
174
- value={vizConfig.autoLoad}
175
- updateField={(_section, _subsection, _key, value) => {
176
- updateConfig({ ...vizConfig, autoLoad: value })
177
- }}
178
- tooltip={
179
- <Tooltip style={{ textTransform: 'none' }}>
180
- <Tooltip.Target>
181
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
182
- </Tooltip.Target>
183
- <Tooltip.Content>
184
- <p>
185
- Check if you would like for all URL filters to automatically select a value when a parent filter
186
- is changed.
187
- </p>
188
- </Tooltip.Content>
189
- </Tooltip>
190
- }
191
- />
192
- )}
193
- </AccordionItemPanel>
194
- </AccordionItem>
195
-
196
- <AccordionItem>
197
- <AccordionItemHeading>
198
- <AccordionItemButton>Filters</AccordionItemButton>
199
- </AccordionItemHeading>
200
- <AccordionItemPanel>
201
- {vizConfig.sharedFilterIndexes.map(index => {
202
- const filter = sharedFilters[index]
203
- return (
204
- <FieldSetWrapper
205
- key={filter.key + index}
206
- fieldName={filter.key}
207
- fieldKey={index}
208
- fieldType='Dashboard Filter'
209
- controls={openControls}
210
- deleteField={() => {
211
- overlay?.actions.openOverlay(
212
- <DeleteFilterModal
213
- removeFilterCompletely={removeFilter}
214
- removeFilterFromViz={index => {
215
- updateConfig({
216
- ...vizConfig,
217
- sharedFilterIndexes: vizConfig.sharedFilterIndexes.filter(i => i !== index)
218
- })
219
- }}
220
- filterIndex={index}
221
- />
222
- )
223
- }}
224
- >
225
- <FilterEditor
226
- filter={filter}
227
- filterIndex={index}
228
- updateFilterProp={(name, value) => {
229
- updateFilterProp(name, index, value)
230
- }}
231
- toggleNestedQueryParameters={checked => {
232
- toggleNestedQueryParameters(index, checked)
233
- }}
234
- config={config}
235
- />
236
- </FieldSetWrapper>
237
- )
238
- })}
239
- <button onClick={addNewFilter} className='btn btn-primary full-width'>
240
- Add Filter
241
- </button>
242
- {canAddExisting ? (
243
- <label>
244
- <span className='edit-label column-heading'>
245
- Select Existing Dashboard Filter
246
- <Tooltip style={{ textTransform: 'none' }}>
247
- <Tooltip.Target>
248
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
249
- </Tooltip.Target>
250
- <Tooltip.Content>
251
- <p>
252
- This feature is indentended to support legacy functionality. Be advised that any change to the
253
- filter in this editor will reflect on the whole dashboard.{' '}
254
- </p>
255
- </Tooltip.Content>
256
- </Tooltip>
257
- </span>
258
- <select
259
- value={''}
260
- onChange={e => {
261
- updateConfig({
262
- ...vizConfig,
263
- sharedFilterIndexes: [...vizConfig.sharedFilterIndexes, e.target.value]
264
- })
265
- setCanAddExisting(false)
266
- }}
267
- >
268
- {[
269
- <option key='select' value=''>
270
- Select
271
- </option>,
272
- ...existingOptions
273
- ]}
274
- </select>
275
- </label>
276
- ) : (
277
- <button onClick={() => setCanAddExisting(true)} className='btn btn-primary full-width mt-2'>
278
- Add Existing Dashboard Filter
279
- </button>
280
- )}
281
- </AccordionItemPanel>
282
- </AccordionItem>
283
- </Accordion>
284
- )
285
- }
286
-
287
- export default DashboardFiltersEditor
1
+ import {
2
+ Accordion,
3
+ AccordionItem,
4
+ AccordionItemButton,
5
+ AccordionItemHeading,
6
+ AccordionItemPanel
7
+ } from 'react-accessible-accordion'
8
+ import { useContext, useMemo, useState } from 'react'
9
+ import { CheckBox, Select, TextField } from '@cdc/core/components/EditorPanel/Inputs'
10
+ import Tooltip from '@cdc/core/components/ui/Tooltip'
11
+ import Icon from '@cdc/core/components/ui/Icon'
12
+ import FieldSetWrapper from '@cdc/core/components/EditorPanel/FieldSetWrapper'
13
+ import FilterEditor from './components/FilterEditor'
14
+ import { DashboardContext, DashboardDispatchContext } from '../../../DashboardContext'
15
+ import _ from 'lodash'
16
+ import { DashboardFilters } from '../../../types/DashboardFilters'
17
+ import { SharedFilter } from '../../../types/SharedFilter'
18
+ import { useGlobalContext } from '@cdc/core/components/GlobalContext'
19
+ import DeleteFilterModal from './components/DeleteFilterModal'
20
+ import { addValuesToDashboardFilters } from '../../../helpers/addValuesToDashboardFilters'
21
+ import { FILTER_STYLE } from '../../../types/FilterStyles'
22
+ import { handleSorting } from '@cdc/core/components/Filters'
23
+ import { removeDashboardFilter } from '../../../helpers/removeDashboardFilter'
24
+
25
+ type DashboardFitlersEditorProps = {
26
+ vizConfig: DashboardFilters
27
+ updateConfig: Function
28
+ }
29
+
30
+ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConfig, updateConfig }) => {
31
+ const { config, loadAPIFilters, data } = useContext(DashboardContext)
32
+ const { overlay } = useGlobalContext()
33
+ const {
34
+ dashboard: { sharedFilters },
35
+ visualizations
36
+ } = config
37
+ const dispatch = useContext(DashboardDispatchContext)
38
+
39
+ const existingOptions = useMemo(() => {
40
+ const sharedFilterIndexes = (config.visualizations[vizConfig.uid] as DashboardFilters).sharedFilterIndexes.map(
41
+ Number
42
+ )
43
+ return config.dashboard.sharedFilters
44
+ ?.map<[number, string]>(({ key }, i) => [i, key])
45
+ .filter(([filterIndex]) => !sharedFilterIndexes.includes(filterIndex)) // filter out already added filters
46
+ .map(([filterIndex, filterName]) => (
47
+ <option key={filterIndex} value={filterIndex}>{`${filterIndex} - ${filterName}`}</option>
48
+ ))
49
+ }, [config.visualizations, vizConfig.uid])
50
+
51
+ const openControls = useState({})
52
+ const [canAddExisting, setCanAddExisting] = useState(false)
53
+
54
+ const updateFilterProp = (prop: string, index: number, value) => {
55
+ const newSharedFilters = _.cloneDeep(sharedFilters)
56
+ const {
57
+ apiEndpoint: oldEndpoint,
58
+ valueSelector: oldValueSelector,
59
+ textSelector: oldTextSelector,
60
+ subgroupValueSelector: oldSubgroupValueSelector,
61
+ subgroupTextSelector: oldSubgroupTextSelector
62
+ } = sharedFilters[index].apiFilter || {}
63
+ const apiFilterChanged =
64
+ value?.apiEndpoint !== oldEndpoint ||
65
+ value?.valueSelector !== oldValueSelector ||
66
+ value?.textSelector !== oldTextSelector ||
67
+ value?.subgroupValueSelector !== oldSubgroupValueSelector ||
68
+ value?.subgroupTextSelector !== oldSubgroupTextSelector
69
+
70
+ newSharedFilters[index][prop] = value
71
+ if (prop === 'columnName') {
72
+ if (newSharedFilters[index].subGrouping) delete newSharedFilters[index].subGrouping
73
+ // changing a data column and want to load the data into the preview options
74
+ const sharedFiltersWithValues = addValuesToDashboardFilters(newSharedFilters, data)
75
+ dispatch({ type: 'SET_SHARED_FILTERS', payload: sharedFiltersWithValues })
76
+ } else if (prop === 'filterStyle') {
77
+ newSharedFilters[index] = {
78
+ ...newSharedFilters[index],
79
+ active: '',
80
+ apiFilter: {
81
+ apiEndpoint: '',
82
+ subgroupValueSelector: '',
83
+ textSelector: '',
84
+ valueSelector: ''
85
+ },
86
+ filterStyle: value
87
+ }
88
+ dispatch({ type: 'SET_SHARED_FILTERS', payload: newSharedFilters })
89
+ } else if (prop === 'apiFilter' && value.apiEndpoint && value.valueSelector && apiFilterChanged) {
90
+ if (sharedFilters[index].filterStyle === FILTER_STYLE.nestedDropdown && value.subgroupValueSelector) {
91
+ newSharedFilters[index].subGrouping = {
92
+ active: '',
93
+ columnName: '',
94
+ setByQueryParameter: '',
95
+ valuesLookup: {}
96
+ }
97
+ }
98
+ // changing a api filter and want to load the api data into the preview.
99
+ // automatically dispatches SET_SHARED_FILTERS
100
+ loadAPIFilters(newSharedFilters, {})
101
+ } else {
102
+ handleSorting(newSharedFilters[index])
103
+ dispatch({ type: 'SET_SHARED_FILTERS', payload: newSharedFilters })
104
+ }
105
+ }
106
+
107
+ const toggleNestedQueryParameters = (index, checked: boolean) => {
108
+ const newSharedFilters = _.cloneDeep(sharedFilters)
109
+ const filter = newSharedFilters[index]
110
+ const isUrlFilter = filter.type === 'urlfilter'
111
+ const groupColumnName = isUrlFilter ? filter.apiFilter.valueSelector : filter.columnName
112
+ const subGroupColumnName = isUrlFilter ? filter.apiFilter.subgroupValueSelector : filter.subGrouping.columnName
113
+ filter.setByQueryParameter = checked ? groupColumnName : undefined
114
+ filter.subGrouping.setByQueryParameter = checked ? subGroupColumnName : undefined
115
+ dispatch({ type: 'SET_SHARED_FILTERS', payload: newSharedFilters })
116
+ }
117
+
118
+ const removeFilter = index => {
119
+ const [newSharedFilters, newVisualizations] = removeDashboardFilter(index, sharedFilters, visualizations)
120
+ const dashboard = { ...config.dashboard, sharedFilters: newSharedFilters }
121
+ dispatch({ type: 'SET_CONFIG', payload: { dashboard, visualizations: newVisualizations } })
122
+ }
123
+
124
+ const addNewFilter = () => {
125
+ const _sharedFilters = _.cloneDeep(sharedFilters) || []
126
+ const columnName = 'New Dashboard Filter ' + (_sharedFilters.length + 1)
127
+ const newFilter = { key: columnName, showDropdown: true, values: [] } as SharedFilter
128
+ dispatch({ type: 'SET_SHARED_FILTERS', payload: [..._sharedFilters, newFilter] })
129
+ updateConfig({ ...vizConfig, sharedFilterIndexes: [...vizConfig.sharedFilterIndexes, _sharedFilters.length] })
130
+ }
131
+
132
+ return (
133
+ <Accordion allowZeroExpanded={true}>
134
+ <AccordionItem>
135
+ <AccordionItemHeading>
136
+ <AccordionItemButton>General</AccordionItemButton>
137
+ </AccordionItemHeading>
138
+ <AccordionItemPanel>
139
+ <Select
140
+ value={vizConfig.filterBehavior}
141
+ label='Filter Behavior'
142
+ updateField={(_section, _subsection, _key, value) => {
143
+ updateConfig({ ...vizConfig, filterBehavior: value })
144
+ }}
145
+ options={['Apply Button', 'Filter Change']}
146
+ tooltip={
147
+ <Tooltip style={{ textTransform: 'none' }}>
148
+ <Tooltip.Target>
149
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
150
+ </Tooltip.Target>
151
+ <Tooltip.Content>
152
+ <p>
153
+ The Apply Button option changes the visualization when the user clicks "apply". The Filter Change
154
+ option immediately changes the visualization when the selection is changed.
155
+ </p>
156
+ </Tooltip.Content>
157
+ </Tooltip>
158
+ }
159
+ />
160
+ {vizConfig.filterBehavior === 'Apply Button' && (
161
+ <TextField
162
+ label='Apply Filter Button Text'
163
+ maxLength={20}
164
+ value={vizConfig.applyFiltersButtonText}
165
+ updateField={(_section, _subsection, _key, value) => {
166
+ updateConfig({ ...vizConfig, applyFiltersButtonText: value })
167
+ }}
168
+ />
169
+ )}
170
+ {vizConfig.filterBehavior === 'Filter Change' && (
171
+ <CheckBox
172
+ label='Auto Load'
173
+ value={vizConfig.autoLoad}
174
+ updateField={(_section, _subsection, _key, value) => {
175
+ updateConfig({ ...vizConfig, autoLoad: value })
176
+ }}
177
+ tooltip={
178
+ <Tooltip style={{ textTransform: 'none' }}>
179
+ <Tooltip.Target>
180
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
181
+ </Tooltip.Target>
182
+ <Tooltip.Content>
183
+ <p>
184
+ Check if you would like for all URL filters to automatically select a value when a parent filter
185
+ is changed.
186
+ </p>
187
+ </Tooltip.Content>
188
+ </Tooltip>
189
+ }
190
+ />
191
+ )}
192
+ </AccordionItemPanel>
193
+ </AccordionItem>
194
+
195
+ <AccordionItem>
196
+ <AccordionItemHeading>
197
+ <AccordionItemButton>Filters</AccordionItemButton>
198
+ </AccordionItemHeading>
199
+ <AccordionItemPanel>
200
+ {vizConfig.sharedFilterIndexes.map(index => {
201
+ const filter = sharedFilters[index]
202
+ return (
203
+ <FieldSetWrapper
204
+ key={filter.key + index}
205
+ fieldName={filter.key}
206
+ fieldKey={index}
207
+ fieldType='Dashboard Filter'
208
+ controls={openControls}
209
+ deleteField={() => {
210
+ overlay?.actions.openOverlay(
211
+ <DeleteFilterModal
212
+ removeFilterCompletely={removeFilter}
213
+ removeFilterFromViz={index => {
214
+ updateConfig({
215
+ ...vizConfig,
216
+ sharedFilterIndexes: vizConfig.sharedFilterIndexes.filter(i => i !== index)
217
+ })
218
+ }}
219
+ filterIndex={index}
220
+ />
221
+ )
222
+ }}
223
+ >
224
+ <FilterEditor
225
+ filter={filter}
226
+ filterIndex={index}
227
+ updateFilterProp={(name, value) => {
228
+ updateFilterProp(name, index, value)
229
+ }}
230
+ toggleNestedQueryParameters={checked => {
231
+ toggleNestedQueryParameters(index, checked)
232
+ }}
233
+ config={config}
234
+ />
235
+ </FieldSetWrapper>
236
+ )
237
+ })}
238
+ <button onClick={addNewFilter} className='btn btn-primary full-width'>
239
+ Add Filter
240
+ </button>
241
+ {canAddExisting ? (
242
+ <label>
243
+ <span className='edit-label column-heading'>
244
+ Select Existing Dashboard Filter
245
+ <Tooltip style={{ textTransform: 'none' }}>
246
+ <Tooltip.Target>
247
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
248
+ </Tooltip.Target>
249
+ <Tooltip.Content>
250
+ <p>
251
+ This feature is indentended to support legacy functionality. Be advised that any change to the
252
+ filter in this editor will reflect on the whole dashboard.{' '}
253
+ </p>
254
+ </Tooltip.Content>
255
+ </Tooltip>
256
+ </span>
257
+ <select
258
+ value={''}
259
+ onChange={e => {
260
+ updateConfig({
261
+ ...vizConfig,
262
+ sharedFilterIndexes: [...vizConfig.sharedFilterIndexes, e.target.value]
263
+ })
264
+ setCanAddExisting(false)
265
+ }}
266
+ >
267
+ {[
268
+ <option key='select' value=''>
269
+ Select
270
+ </option>,
271
+ ...existingOptions
272
+ ]}
273
+ </select>
274
+ </label>
275
+ ) : (
276
+ <button onClick={() => setCanAddExisting(true)} className='btn btn-primary full-width mt-2'>
277
+ Add Existing Dashboard Filter
278
+ </button>
279
+ )}
280
+ </AccordionItemPanel>
281
+ </AccordionItem>
282
+ </Accordion>
283
+ )
284
+ }
285
+
286
+ export default DashboardFiltersEditor