@cdc/dashboard 4.24.4 → 4.24.7

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 (75) hide show
  1. package/dist/cdcdashboard.js +179228 -141419
  2. package/examples/custom/css/respiratory.css +236 -0
  3. package/examples/custom/js/respiratory.js +242 -0
  4. package/examples/default-multi-dataset-shared-filter.json +1729 -0
  5. package/examples/ed-visits-county-file.json +618 -0
  6. package/examples/filtered-dash.json +6 -21
  7. package/index.html +12 -3
  8. package/package.json +12 -11
  9. package/src/CdcDashboard.tsx +5 -1
  10. package/src/CdcDashboardComponent.tsx +156 -334
  11. package/src/DashboardContext.tsx +9 -1
  12. package/src/_stories/Dashboard.stories.tsx +31 -3
  13. package/src/_stories/_mock/dashboard-gallery.json +534 -523
  14. package/src/_stories/_mock/markup-include.json +78 -0
  15. package/src/_stories/_mock/multi-dashboards.json +914 -0
  16. package/src/_stories/_mock/multi-viz.json +2 -3
  17. package/src/_stories/_mock/pivot-filter.json +15 -11
  18. package/src/_stories/_mock/standalone-table.json +2 -0
  19. package/src/components/CollapsibleVisualizationRow.tsx +44 -0
  20. package/src/components/Column.tsx +1 -1
  21. package/src/components/DashboardFilters/DashboardFilters.tsx +80 -0
  22. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +218 -0
  23. package/src/components/DashboardFilters/DashboardFiltersEditor/components/DeleteFilterModal.tsx +48 -0
  24. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +367 -0
  25. package/src/components/DashboardFilters/DashboardFiltersEditor/index.ts +1 -0
  26. package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +143 -0
  27. package/src/components/DashboardFilters/index.ts +3 -0
  28. package/src/components/DataDesignerModal.tsx +9 -9
  29. package/src/components/ExpandCollapseButtons.tsx +20 -0
  30. package/src/components/Header/Header.tsx +1 -97
  31. package/src/components/MultiConfigTabs/MultiConfigTabs.tsx +4 -4
  32. package/src/components/MultiConfigTabs/MultiTabs.tsx +3 -2
  33. package/src/components/Row.tsx +52 -19
  34. package/src/components/Toggle/Toggle.tsx +2 -4
  35. package/src/components/VisualizationRow.tsx +96 -29
  36. package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +116 -0
  37. package/src/components/VisualizationsPanel/index.ts +1 -0
  38. package/src/components/VisualizationsPanel/visualizations-panel-styles.css +12 -0
  39. package/src/components/Widget.tsx +26 -90
  40. package/src/helpers/apiFilterHelpers.ts +51 -0
  41. package/src/helpers/changeFilterActive.ts +30 -0
  42. package/src/helpers/filterData.ts +16 -56
  43. package/src/helpers/generateValuesForFilter.ts +1 -1
  44. package/src/helpers/getAutoLoadVisualization.ts +11 -0
  45. package/src/helpers/getFilteredData.ts +4 -2
  46. package/src/helpers/getVizConfig.ts +23 -2
  47. package/src/helpers/getVizRowColumnLocator.ts +2 -1
  48. package/src/helpers/hasDashboardApplyBehavior.ts +5 -0
  49. package/src/helpers/iconHash.tsx +3 -3
  50. package/src/helpers/mapDataToConfig.ts +29 -0
  51. package/src/helpers/processData.ts +2 -3
  52. package/src/helpers/reloadURLHelpers.ts +68 -0
  53. package/src/helpers/tests/filterData.test.ts +1 -93
  54. package/src/scss/editor-panel.scss +1 -1
  55. package/src/scss/grid.scss +34 -27
  56. package/src/scss/main.scss +41 -3
  57. package/src/scss/variables.scss +4 -0
  58. package/src/store/dashboard.actions.ts +9 -10
  59. package/src/store/dashboard.reducer.ts +41 -13
  60. package/src/types/APIFilter.ts +1 -4
  61. package/src/types/ConfigRow.ts +2 -0
  62. package/src/types/Dashboard.ts +1 -1
  63. package/src/types/DashboardConfig.ts +2 -4
  64. package/src/types/DashboardFilters.ts +7 -0
  65. package/src/types/InitialState.ts +1 -1
  66. package/src/types/MultiDashboard.ts +2 -2
  67. package/src/types/SharedFilter.ts +2 -5
  68. package/src/types/Tab.ts +1 -1
  69. package/LICENSE +0 -201
  70. package/src/components/EditorWrapper/EditorWrapper.tsx +0 -52
  71. package/src/components/EditorWrapper/editor-wrapper.style.css +0 -13
  72. package/src/components/Filters.tsx +0 -88
  73. package/src/components/Header/FilterModal.tsx +0 -506
  74. package/src/components/VisualizationsPanel.tsx +0 -72
  75. package/src/helpers/getApiFilterKey.ts +0 -5
@@ -164,7 +164,7 @@
164
164
  },
165
165
  "table": {
166
166
  "label": "Data Table",
167
- "expanded": true,
167
+ "expanded": false,
168
168
  "limitHeight": false,
169
169
  "height": "",
170
170
  "caption": "",
@@ -366,11 +366,10 @@
366
366
  },
367
367
  "table": {
368
368
  "label": "Data Table",
369
- "show": true,
369
+ "show": false,
370
370
  "showDownloadUrl": false,
371
371
  "showVertical": true
372
372
  },
373
- "newViz": true,
374
373
  "datasets": {},
375
374
  "type": "dashboard",
376
375
  "runtime": {},
@@ -1,16 +1,7 @@
1
1
  {
2
2
  "dashboard": {
3
3
  "theme": "theme-blue",
4
- "sharedFilters": [
5
- {
6
- "key": "Race",
7
- "type": "datafilter",
8
- "showDropdown": true,
9
- "columnName": "Race",
10
- "pivot": "Age-adjusted rate",
11
- "usedBy": ["table1707935263149"]
12
- }
13
- ]
4
+ "sharedFilters": []
14
5
  },
15
6
  "rows": [
16
7
  [
@@ -32,7 +23,11 @@
32
23
  "show": true,
33
24
  "showDownloadUrl": false,
34
25
  "showVertical": true,
35
- "expanded": true
26
+ "expanded": true,
27
+ "pivot": {
28
+ "columnName": "Race",
29
+ "valueColumn": "Age-adjusted rate"
30
+ }
36
31
  },
37
32
  "columns": {},
38
33
  "dataFormat": {},
@@ -41,6 +36,15 @@
41
36
  "horizontal": false,
42
37
  "series": false
43
38
  },
39
+ "filters": [
40
+ {
41
+ "filterStyle": "multi-select",
42
+ "label": "Race",
43
+ "columnName": "Race",
44
+ "showDropdown": true
45
+ }
46
+ ],
47
+ "filterBehavior": "Filter Change",
44
48
  "formattedData": [
45
49
  {
46
50
  "Race": "Hispanic or Latino",
@@ -17,6 +17,8 @@
17
17
  "newViz": true,
18
18
  "openModal": false,
19
19
  "uid": "table1707840146431",
20
+ "filters": [],
21
+ "filterBehavior": "Filter Change",
20
22
  "table": {
21
23
  "label": "Data Table",
22
24
  "show": true,
@@ -0,0 +1,44 @@
1
+ import React, { useState, useEffect } from 'react'
2
+ import Icon from '../../../core/components/ui/Icon'
3
+
4
+ type CollapsableVizRow = {
5
+ allExpanded: boolean
6
+ children: React.ReactNode
7
+ fontSize: string
8
+ groupName: string
9
+ currentViewport: string
10
+ }
11
+ const CollapsibleVisualizationRow: React.FC<CollapsableVizRow> = ({ allExpanded, fontSize, groupName, currentViewport, children }) => {
12
+ const [isExpanded, setIsExpanded] = useState(allExpanded)
13
+ const fontSizes = { small: 16, medium: 18, large: 20 }
14
+ const titleFontSize = ['sm', 'xs', 'xxs'].includes(currentViewport) ? '13px' : `${fontSizes[fontSize]}px`
15
+
16
+ useEffect(() => {
17
+ setIsExpanded(allExpanded)
18
+ }, [allExpanded])
19
+
20
+ return (
21
+ <>
22
+ <div
23
+ style={{ fontSize: titleFontSize }}
24
+ role='button'
25
+ className={`multi-visualiation-heading${isExpanded ? '' : ' collapsed'} h4`}
26
+ onClick={() => {
27
+ setIsExpanded(!isExpanded)
28
+ }}
29
+ tabIndex={0}
30
+ onKeyDown={e => {
31
+ if (e.keyCode === 13) {
32
+ setIsExpanded(!isExpanded)
33
+ }
34
+ }}
35
+ >
36
+ <Icon display={isExpanded ? 'minus' : 'plus'} base />
37
+ {groupName}
38
+ </div>
39
+ {isExpanded && children}
40
+ </>
41
+ )
42
+ }
43
+
44
+ export default CollapsibleVisualizationRow
@@ -40,7 +40,7 @@ const Column = ({ data, rowIdx, colIdx }) => {
40
40
  return (
41
41
  <div className={classNames.join(' ')} ref={drop}>
42
42
  {widget ? (
43
- <Widget data={{ rowIdx, colIdx, ...widget }} type={widget.visualizationType ?? widget.general?.geoType} />
43
+ <Widget widgetConfig={{ rowIdx, colIdx, ...widget }} type={widget.visualizationType ?? widget.general?.geoType} />
44
44
  ) : (
45
45
  <p className='builder-column__text'>
46
46
  Drag and drop <br /> visualization
@@ -0,0 +1,80 @@
1
+ import { SharedFilter } from '../../types/SharedFilter'
2
+ import { APIFilterDropdowns } from './DashboardFiltersWrapper'
3
+
4
+ type DashboardFilterProps = {
5
+ show: number[]
6
+ filters: SharedFilter[]
7
+ apiFilterDropdowns: APIFilterDropdowns
8
+ handleOnChange: Function
9
+ }
10
+
11
+ const DashboardFilters: React.FC<DashboardFilterProps> = ({ show, filters, apiFilterDropdowns, handleOnChange }) => {
12
+ const nullVal = (singleFilter: SharedFilter) => {
13
+ const val = singleFilter.queuedActive || singleFilter.active
14
+ return val === null || val === undefined || val === ''
15
+ }
16
+ return (
17
+ <>
18
+ {filters.map((singleFilter, filterIndex) => {
19
+ if ((singleFilter.type !== 'urlfilter' && !singleFilter.showDropdown) || (show && !show.includes(filterIndex))) return <></>
20
+ const values: JSX.Element[] = []
21
+ const multiValues = []
22
+ if (singleFilter.resetLabel) {
23
+ values.push(
24
+ <option key={`${singleFilter.resetLabel}-option`} value={singleFilter.resetLabel}>
25
+ {singleFilter.resetLabel}
26
+ </option>
27
+ )
28
+ }
29
+ const _key = singleFilter.apiFilter?.apiEndpoint
30
+ if (_key && apiFilterDropdowns[_key]) {
31
+ // URL Filter
32
+ apiFilterDropdowns[_key].forEach(({ text, value }, index) => {
33
+ values.push(
34
+ <option key={`${value}-option-${index}`} value={value}>
35
+ {text}
36
+ </option>
37
+ )
38
+ })
39
+ } else {
40
+ // Data Filter
41
+ singleFilter.values?.forEach((filterOption, index) => {
42
+ const labeledOpt = singleFilter.labels && singleFilter.labels[filterOption]
43
+ values.push(
44
+ <option key={`${singleFilter.key}-option-${index}`} value={filterOption}>
45
+ {labeledOpt || filterOption}
46
+ </option>
47
+ )
48
+ multiValues.push({ value: filterOption, label: labeledOpt || filterOption })
49
+ })
50
+ }
51
+
52
+ return (
53
+ <div className='cove-dashboard-filters' key={`${singleFilter.key}-filtersection-${filterIndex}`}>
54
+ <section className='dashboard-filters-section'>
55
+ <label htmlFor={`filter-${filterIndex}`}>{singleFilter.key}</label>
56
+ <select
57
+ id={`filter-${filterIndex}`}
58
+ className='filter-select'
59
+ data-index='0'
60
+ value={singleFilter.queuedActive || singleFilter.active}
61
+ onChange={val => {
62
+ handleOnChange(filterIndex, val.target.value)
63
+ }}
64
+ >
65
+ {nullVal(singleFilter) && !singleFilter.resetLabel && (
66
+ <option value='' key='select'>
67
+ {'-Select-'}
68
+ </option>
69
+ )}
70
+ {values}
71
+ </select>
72
+ </section>
73
+ </div>
74
+ )
75
+ })}
76
+ </>
77
+ )
78
+ }
79
+
80
+ export default DashboardFilters
@@ -0,0 +1,218 @@
1
+ import { Accordion, AccordionItem, AccordionItemButton, AccordionItemHeading, AccordionItemPanel } from 'react-accessible-accordion'
2
+ import { useContext, useMemo, useState } from 'react'
3
+ import { CheckBox, Select } from '@cdc/core/components/EditorPanel/Inputs'
4
+ import Tooltip from '@cdc/core/components/ui/Tooltip'
5
+ import Icon from '@cdc/core/components/ui/Icon'
6
+ import FieldSetWrapper from '@cdc/core/components/EditorPanel/FieldSetWrapper'
7
+ import FilterEditor from './components/FilterEditor'
8
+ import { AnyVisualization } from '@cdc/core/types/Visualization'
9
+ import { DashboardContext, DashboardDispatchContext } from '../../../DashboardContext'
10
+ import _ from 'lodash'
11
+ import { DashboardFilters } from '../../../types/DashboardFilters'
12
+ import { SharedFilter } from '../../../types/SharedFilter'
13
+ import { addValuesToFilters } from '@cdc/core/helpers/addValuesToFilters'
14
+ import { useGlobalContext } from '@cdc/core/components/GlobalContext'
15
+ import DeleteFilterModal from './components/DeleteFilterModal'
16
+
17
+ type DashboardFitlersEditorProps = {
18
+ vizConfig: DashboardFilters
19
+ updateConfig: Function
20
+ }
21
+
22
+ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConfig, updateConfig }) => {
23
+ const { config, loadAPIFilters, data } = useContext(DashboardContext)
24
+ const { overlay } = useGlobalContext()
25
+ const {
26
+ dashboard: { sharedFilters },
27
+ visualizations
28
+ } = config
29
+ const dispatch = useContext(DashboardDispatchContext)
30
+
31
+ const existingOptions = useMemo(() => {
32
+ const sharedFilterIndexes = (config.visualizations[vizConfig.uid] as DashboardFilters).sharedFilterIndexes.map(Number)
33
+ return config.dashboard.sharedFilters
34
+ .map<[number, string]>(({ key }, i) => [i, key])
35
+ .filter(([filterIndex]) => !sharedFilterIndexes.includes(filterIndex)) // filter out already added filters
36
+ .map(([filterIndex, filterName]) => <option key={filterIndex} value={filterIndex}>{`${filterIndex} - ${filterName}`}</option>)
37
+ }, [config.visualizations, vizConfig.uid])
38
+
39
+ const openControls = useState({})
40
+ const [canAddExisting, setCanAddExisting] = useState(false)
41
+
42
+ const updateFilterProp = (prop: string, index: number, value) => {
43
+ const newSharedFilters = _.cloneDeep(sharedFilters)
44
+ const oldEndpoint = sharedFilters[index].apiFilter?.apiEndpoint
45
+ const oldAPIValueSelector = sharedFilters[index].apiFilter?.valueSelector
46
+ const apiFilterChanged = value.apiEndpoint !== oldEndpoint || value.valueSelector !== oldAPIValueSelector
47
+ newSharedFilters[index][prop] = value
48
+ if (prop === 'columnName') {
49
+ // changing a data column and want to load the data into the preview options
50
+ const sharedFiltersWithValues = addValuesToFilters<SharedFilter>(newSharedFilters, data)
51
+ dispatch({ type: 'SET_SHARED_FILTERS', payload: sharedFiltersWithValues })
52
+ } else if (prop === 'apiFilter' && value.apiEndpoint && value.valueSelector && apiFilterChanged) {
53
+ // changing a api filter and want to load the api data into the preview.
54
+ // automatically dispatches SET_SHARED_FILTERS
55
+ loadAPIFilters(newSharedFilters, {})
56
+ } else {
57
+ dispatch({ type: 'SET_SHARED_FILTERS', payload: newSharedFilters })
58
+ }
59
+ }
60
+
61
+ const removeFilter = index => {
62
+ const newSharedFilters = _.cloneDeep(sharedFilters)
63
+
64
+ newSharedFilters.splice(index, 1)
65
+ const shiftDownIndexes = Object.keys(sharedFilters).slice(index + 1)
66
+ const anyViz: Record<string, AnyVisualization> = visualizations
67
+ Object.keys(anyViz).forEach(vizKey => {
68
+ const viz = anyViz[vizKey]
69
+ if (viz.type === 'dashboardFilters') {
70
+ // shift the indexes down
71
+ const sharedFilterIndexes = viz.sharedFilterIndexes
72
+ .filter(filterIndex => filterIndex != index)
73
+ .map(filterIndex => {
74
+ if (shiftDownIndexes.includes(filterIndex.toString())) {
75
+ return filterIndex - 1
76
+ }
77
+ return filterIndex
78
+ })
79
+ dispatch({ type: 'UPDATE_VISUALIZATION', payload: { vizKey, configureData: { sharedFilterIndexes } } })
80
+ }
81
+ })
82
+ dispatch({ type: 'SET_SHARED_FILTERS', payload: newSharedFilters })
83
+ }
84
+
85
+ const addNewFilter = () => {
86
+ const _sharedFilters = _.cloneDeep(sharedFilters) || []
87
+ const columnName = 'New Dashboard Filter ' + (_sharedFilters.length + 1)
88
+ const newFilter = { key: columnName, showDropdown: true, values: [] } as SharedFilter
89
+ dispatch({ type: 'SET_SHARED_FILTERS', payload: [..._sharedFilters, newFilter] })
90
+ updateConfig({ ...vizConfig, sharedFilterIndexes: [...vizConfig.sharedFilterIndexes, _sharedFilters.length] })
91
+ }
92
+
93
+ return (
94
+ <Accordion allowZeroExpanded={true}>
95
+ <AccordionItem>
96
+ <AccordionItemHeading>
97
+ <AccordionItemButton>General</AccordionItemButton>
98
+ </AccordionItemHeading>
99
+ <AccordionItemPanel>
100
+ <Select
101
+ value={vizConfig.filterBehavior}
102
+ label='Filter Behavior'
103
+ updateField={(_section, _subsection, _key, value) => {
104
+ updateConfig({ ...vizConfig, filterBehavior: value })
105
+ }}
106
+ options={['Apply Button', 'Filter Change']}
107
+ tooltip={
108
+ <Tooltip style={{ textTransform: 'none' }}>
109
+ <Tooltip.Target>
110
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
111
+ </Tooltip.Target>
112
+ <Tooltip.Content>
113
+ <p>The Apply Button option changes the visualization when the user clicks "apply". The Filter Change option immediately changes the visualization when the selection is changed.</p>
114
+ </Tooltip.Content>
115
+ </Tooltip>
116
+ }
117
+ />
118
+ {vizConfig.filterBehavior === 'Filter Change' && (
119
+ <CheckBox
120
+ label='Auto Load'
121
+ value={vizConfig.autoLoad}
122
+ updateField={(_section, _subsection, _key, value) => {
123
+ updateConfig({ ...vizConfig, autoLoad: value })
124
+ }}
125
+ tooltip={
126
+ <Tooltip style={{ textTransform: 'none' }}>
127
+ <Tooltip.Target>
128
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
129
+ </Tooltip.Target>
130
+ <Tooltip.Content>
131
+ <p>Check if you would like for all URL filters to automatically select a value when a parent filter is changed.</p>
132
+ </Tooltip.Content>
133
+ </Tooltip>
134
+ }
135
+ />
136
+ )}
137
+ </AccordionItemPanel>
138
+ </AccordionItem>
139
+
140
+ <AccordionItem>
141
+ <AccordionItemHeading>
142
+ <AccordionItemButton>Filters</AccordionItemButton>
143
+ </AccordionItemHeading>
144
+ <AccordionItemPanel>
145
+ {vizConfig.sharedFilterIndexes.map(index => {
146
+ const filter = sharedFilters[index]
147
+ return (
148
+ <FieldSetWrapper
149
+ key={filter.key + index}
150
+ fieldName={filter.key}
151
+ fieldKey={index}
152
+ fieldType='Dashboard Filter'
153
+ controls={openControls}
154
+ deleteField={() => {
155
+ overlay?.actions.openOverlay(
156
+ <DeleteFilterModal
157
+ removeFilterCompletely={removeFilter}
158
+ removeFilterFromViz={index => {
159
+ updateConfig({ ...vizConfig, sharedFilterIndexes: vizConfig.sharedFilterIndexes.filter(i => i !== index) })
160
+ }}
161
+ filterIndex={index}
162
+ />
163
+ )
164
+ }}
165
+ >
166
+ <FilterEditor
167
+ filter={filter}
168
+ updateFilterProp={(name, value) => {
169
+ updateFilterProp(name, index, value)
170
+ }}
171
+ config={config}
172
+ />
173
+ </FieldSetWrapper>
174
+ )
175
+ })}
176
+ <button onClick={addNewFilter} className='btn btn-primary full-width'>
177
+ Add Filter
178
+ </button>
179
+ {canAddExisting ? (
180
+ <label>
181
+ <span className='edit-label column-heading'>
182
+ Select Existing Dashboard Filter
183
+ <Tooltip style={{ textTransform: 'none' }}>
184
+ <Tooltip.Target>
185
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
186
+ </Tooltip.Target>
187
+ <Tooltip.Content>
188
+ <p>This feature is indentended to support legacy functionality. Be advised that any change to the filter in this editor will reflect on the whole dashboard. </p>
189
+ </Tooltip.Content>
190
+ </Tooltip>
191
+ </span>
192
+ <select
193
+ value={''}
194
+ onChange={e => {
195
+ updateConfig({ ...vizConfig, sharedFilterIndexes: [...vizConfig.sharedFilterIndexes, e.target.value] })
196
+ setCanAddExisting(false)
197
+ }}
198
+ >
199
+ {[
200
+ <option key='select' value=''>
201
+ Select
202
+ </option>,
203
+ ...existingOptions
204
+ ]}
205
+ </select>
206
+ </label>
207
+ ) : (
208
+ <button onClick={() => setCanAddExisting(true)} className='btn btn-primary full-width'>
209
+ Add Existing Dashboard Filter
210
+ </button>
211
+ )}
212
+ </AccordionItemPanel>
213
+ </AccordionItem>
214
+ </Accordion>
215
+ )
216
+ }
217
+
218
+ export default DashboardFiltersEditor
@@ -0,0 +1,48 @@
1
+ import { useGlobalContext } from '@cdc/core/components/GlobalContext'
2
+ import Modal from '@cdc/core/components/ui/Modal'
3
+ import { DashboardContext } from '../../../../DashboardContext'
4
+ import { useContext } from 'react'
5
+ import { DashboardFilters } from '../../../../types/DashboardFilters'
6
+
7
+ type DeleteFilterProps = {
8
+ removeFilterCompletely: (number) => void
9
+ removeFilterFromViz: (number) => void
10
+ filterIndex: number
11
+ }
12
+
13
+ const DeleteFilterModal: React.FC<DeleteFilterProps> = ({ removeFilterCompletely, removeFilterFromViz, filterIndex }) => {
14
+ const { overlay } = useGlobalContext()
15
+ const { config } = useContext(DashboardContext)
16
+ const filterUsedByMany = Object.values(config.visualizations).filter(viz => (viz as DashboardFilters).sharedFilterIndexes?.map(Number).includes(Number(filterIndex))).length > 1
17
+
18
+ const message = filterUsedByMany ? 'This filter is used by multiple visualizations. You can either delete the filter from this visualization only or you can delete the filter completely, which will also remove it from other visualizations.' : 'Are you sure you want to delete this filter?'
19
+ return (
20
+ <Modal showClose={true}>
21
+ <Modal.Content>
22
+ <p>{message}</p>
23
+ {filterUsedByMany && (
24
+ <button
25
+ className='btn btn-warning'
26
+ onClick={() => {
27
+ removeFilterFromViz(filterIndex)
28
+ overlay?.actions.toggleOverlay()
29
+ }}
30
+ >
31
+ Delete from Visualization
32
+ </button>
33
+ )}
34
+ <button
35
+ className='btn btn-danger'
36
+ onClick={() => {
37
+ removeFilterCompletely(filterIndex)
38
+ overlay?.actions.toggleOverlay()
39
+ }}
40
+ >
41
+ Delete{filterUsedByMany ? ' Completely' : ''}
42
+ </button>
43
+ </Modal.Content>
44
+ </Modal>
45
+ )
46
+ }
47
+
48
+ export default DeleteFilterModal