@cdc/dashboard 4.26.1 → 4.26.3

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 (76) hide show
  1. package/LICENSE +201 -0
  2. package/dist/cdcdashboard-8NmHlKRI.es.js +15 -0
  3. package/dist/cdcdashboard-BPoPzKPz.es.js +6 -0
  4. package/dist/{cdcdashboard-dgT_1dIT.es.js → cdcdashboard-DQ00cQCm.es.js} +1 -20
  5. package/dist/cdcdashboard-jiQQPkty.es.js +6 -0
  6. package/dist/cdcdashboard-vr9HZwRt.es.js +6 -0
  7. package/dist/cdcdashboard.js +80971 -83096
  8. package/examples/custom/css/respiratory.css +1 -1
  9. package/examples/data/data-with-metadata.json +18 -0
  10. package/examples/default.json +492 -132
  11. package/examples/nested-dropdown.json +6985 -0
  12. package/examples/private/abc.json +467 -0
  13. package/examples/private/dash.json +12696 -0
  14. package/examples/private/inline-markup.json +775 -0
  15. package/examples/private/npcr.json +1 -0
  16. package/examples/private/recent-update.json +1456 -0
  17. package/examples/private/test.json +125407 -0
  18. package/examples/private/timeline-data.json +4994 -0
  19. package/examples/private/timeline.json +1708 -0
  20. package/examples/private/toggle.json +10137 -0
  21. package/examples/test-api-filter-reset.json +8 -4
  22. package/examples/tp5-gauges.json +196 -0
  23. package/examples/tp5-test.json +266 -0
  24. package/index.html +1 -29
  25. package/package.json +38 -40
  26. package/src/CdcDashboard.tsx +2 -1
  27. package/src/CdcDashboardComponent.tsx +47 -30
  28. package/src/_stories/Dashboard.DataSetup.stories.tsx +8 -2
  29. package/src/_stories/Dashboard.Pages.stories.tsx +22 -0
  30. package/src/_stories/Dashboard.stories.tsx +4501 -80
  31. package/src/_stories/_mock/dashboard-line-chart-angles.json +1030 -0
  32. package/src/_stories/_mock/tab-simple-filter.json +153 -0
  33. package/src/_stories/_mock/tp5-test.json +267 -0
  34. package/src/components/DashboardFilters/DashboardFilters.tsx +19 -3
  35. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +10 -4
  36. package/src/components/DashboardFilters/DashboardFiltersEditor/components/APIModal.tsx +1 -1
  37. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +6 -3
  38. package/src/components/DashboardFilters/DashboardFiltersEditor/components/NestedDropDownDashboard.tsx +13 -8
  39. package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +8 -8
  40. package/src/components/DashboardFilters/_stories/DashboardFilters.stories.tsx +1 -1
  41. package/src/components/DashboardFilters/dashboardfilter.styles.css +3 -3
  42. package/src/components/DataDesignerModal.tsx +2 -2
  43. package/src/components/Header/Header.tsx +27 -5
  44. package/src/components/Header/index.scss +1 -1
  45. package/src/components/MultiConfigTabs/multiconfigtabs.styles.css +6 -6
  46. package/src/components/Row.tsx +21 -0
  47. package/src/components/Toggle/toggle-style.css +7 -7
  48. package/src/components/VisualizationRow.tsx +42 -29
  49. package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +1 -71
  50. package/src/components/VisualizationsPanel/visualizations-panel-styles.css +2 -2
  51. package/src/components/Widget/Widget.tsx +2 -2
  52. package/src/components/Widget/widget.styles.css +12 -12
  53. package/src/data/initial-state.js +1 -1
  54. package/src/helpers/addValuesToDashboardFilters.ts +17 -11
  55. package/src/helpers/addVisualization.ts +71 -0
  56. package/src/helpers/apiFilterHelpers.ts +28 -32
  57. package/src/helpers/formatConfigBeforeSave.ts +1 -1
  58. package/src/helpers/getVizConfig.ts +13 -3
  59. package/src/helpers/iconHash.tsx +45 -36
  60. package/src/helpers/processDataLegacy.ts +19 -14
  61. package/src/helpers/tests/addValuesToDashboardFilters.test.ts +141 -44
  62. package/src/helpers/tests/addVisualization.test.ts +52 -0
  63. package/src/helpers/tests/apiFilterHelpers.test.ts +523 -420
  64. package/src/helpers/tests/formatConfigBeforeSave.test.ts +81 -1
  65. package/src/scss/editor-panel.scss +1 -1
  66. package/src/scss/main.scss +169 -41
  67. package/src/store/dashboard.reducer.ts +1 -1
  68. package/src/test/CdcDashboard.test.jsx +2 -2
  69. package/src/test/CdcDashboardComponent.test.tsx +74 -0
  70. package/src/types/FilterStyles.ts +2 -1
  71. package/tests/fixtures/dashboard-config-with-metadata.json +89 -0
  72. package/vite.config.js +7 -1
  73. package/dist/cdcdashboard-BnB1QM5d.es.js +0 -361528
  74. package/dist/cdcdashboard-Ct2SB0vL.es.js +0 -231049
  75. package/dist/cdcdashboard-D6CG2-Hb.es.js +0 -39377
  76. package/dist/cdcdashboard-MXgURbdZ.es.js +0 -39194
@@ -0,0 +1,153 @@
1
+ {
2
+ "dashboard": {
3
+ "theme": "theme-blue",
4
+ "sharedFilters": [
5
+ {
6
+ "key": "category",
7
+ "showDropdown": true,
8
+ "filterStyle": "tab-simple",
9
+ "values": ["Category A", "Category B", "Category C"],
10
+ "orderedValues": ["Category A", "Category B", "Category C"],
11
+ "type": "datafilter",
12
+ "columnName": "category",
13
+ "tier": 1,
14
+ "order": "cust",
15
+ "defaultValue": "Category A"
16
+ }
17
+ ]
18
+ },
19
+ "rows": [
20
+ {
21
+ "columns": [
22
+ {
23
+ "width": 12,
24
+ "widget": "dashboardFilters1"
25
+ }
26
+ ]
27
+ },
28
+ {
29
+ "columns": [
30
+ {
31
+ "width": 12,
32
+ "widget": "chart1"
33
+ }
34
+ ]
35
+ }
36
+ ],
37
+ "visualizations": {
38
+ "dashboardFilters1": {
39
+ "filters": [],
40
+ "filterBehavior": "Filter Change",
41
+ "newViz": true,
42
+ "uid": "dashboardFilters1",
43
+ "type": "dashboardFilters",
44
+ "sharedFilterIndexes": [0],
45
+ "visualizationType": "dashboardFilters"
46
+ },
47
+ "chart1": {
48
+ "filters": [],
49
+ "filterBehavior": "Filter Change",
50
+ "uid": "chart1",
51
+ "type": "chart",
52
+ "visualizationType": "Bar",
53
+ "title": "Sales by Category",
54
+ "showTitle": true,
55
+ "theme": "theme-blue",
56
+ "animate": false,
57
+ "dataKey": "./tab-simple-data.json",
58
+ "dataDescription": {
59
+ "horizontal": false,
60
+ "series": false
61
+ },
62
+ "xAxis": {
63
+ "dataKey": "product",
64
+ "type": "categorical",
65
+ "hideAxis": false,
66
+ "hideLabel": false,
67
+ "hideTicks": false,
68
+ "size": 75,
69
+ "tickRotation": 0,
70
+ "labelColor": "#1c1d1f",
71
+ "tickLabelColor": "#1c1d1f",
72
+ "tickColor": "#1c1d1f",
73
+ "axisPadding": 200,
74
+ "padding": 5,
75
+ "sortDates": false,
76
+ "anchors": []
77
+ },
78
+ "yAxis": {
79
+ "hideAxis": false,
80
+ "hideLabel": false,
81
+ "hideTicks": false,
82
+ "size": 50,
83
+ "gridLines": false,
84
+ "labelColor": "#1c1d1f",
85
+ "tickLabelColor": "#1c1d1f",
86
+ "tickColor": "#1c1d1f",
87
+ "anchors": [],
88
+ "categories": []
89
+ },
90
+ "series": [
91
+ {
92
+ "dataKey": "sales",
93
+ "type": "Bar",
94
+ "axis": "Left",
95
+ "tooltip": true
96
+ }
97
+ ],
98
+ "orientation": "vertical",
99
+ "general": {
100
+ "showZeroValueData": true,
101
+ "palette": {
102
+ "name": "qualitative_bold",
103
+ "version": "1.0"
104
+ }
105
+ },
106
+ "columns": {},
107
+ "legend": {
108
+ "hide": true
109
+ },
110
+ "table": {
111
+ "label": "Data Table",
112
+ "show": false,
113
+ "sharedFilterColumns": ["category"]
114
+ },
115
+ "heights": {
116
+ "vertical": 300,
117
+ "horizontal": 750
118
+ },
119
+ "visual": {
120
+ "border": true,
121
+ "accent": true,
122
+ "background": true
123
+ },
124
+ "tooltips": {
125
+ "opacity": 90,
126
+ "singleSeries": false
127
+ },
128
+ "barThickness": 0.35
129
+ }
130
+ },
131
+ "datasets": {
132
+ "./tab-simple-data.json": {
133
+ "data": [
134
+ { "category": "Category A", "product": "Widget", "sales": "120" },
135
+ { "category": "Category A", "product": "Gadget", "sales": "85" },
136
+ { "category": "Category A", "product": "Doohickey", "sales": "210" },
137
+ { "category": "Category B", "product": "Widget", "sales": "95" },
138
+ { "category": "Category B", "product": "Gadget", "sales": "150" },
139
+ { "category": "Category B", "product": "Doohickey", "sales": "60" },
140
+ { "category": "Category C", "product": "Widget", "sales": "175" },
141
+ { "category": "Category C", "product": "Gadget", "sales": "110" },
142
+ { "category": "Category C", "product": "Doohickey", "sales": "140" }
143
+ ],
144
+ "dataFileSize": 500,
145
+ "dataFileName": "./tab-simple-data.json",
146
+ "dataFileSourceType": "file",
147
+ "dataFileFormat": "JSON",
148
+ "preview": true
149
+ }
150
+ },
151
+ "type": "dashboard",
152
+ "version": "4.26.1"
153
+ }
@@ -0,0 +1,267 @@
1
+ {
2
+ "type": "dashboard",
3
+ "title": "TP5 Alignment Test Dashboard",
4
+ "description": "Testing alignment of TP5 Waffles, Data Bites, and Gauges",
5
+ "data": [
6
+ {
7
+ "Category": "Adults",
8
+ "Vaccination Rate": "68.5",
9
+ "Insured Rate": "87.2",
10
+ "Screening Rate": "72.8"
11
+ },
12
+ {
13
+ "Category": "Seniors",
14
+ "Vaccination Rate": "82.3",
15
+ "Insured Rate": "95.1",
16
+ "Screening Rate": "84.6"
17
+ },
18
+ {
19
+ "Category": "Youth",
20
+ "Vaccination Rate": "54.2",
21
+ "Insured Rate": "92.4",
22
+ "Screening Rate": "65.3"
23
+ }
24
+ ],
25
+ "dashboard": {
26
+ "filters": []
27
+ },
28
+ "rows": [
29
+ [
30
+ { "width": 4, "widget": "waffle1" },
31
+ { "width": 4, "widget": "waffle2" },
32
+ { "width": 4, "widget": "waffle3" }
33
+ ],
34
+ [
35
+ { "width": 4, "widget": "bite1" },
36
+ { "width": 4, "widget": "bite2" },
37
+ { "width": 4, "widget": "bite3" }
38
+ ],
39
+ [
40
+ { "width": 4, "widget": "gauge1" },
41
+ { "width": 4, "widget": "gauge2" },
42
+ { "width": 4, "widget": "gauge3" }
43
+ ]
44
+ ],
45
+ "visualizations": {
46
+ "waffle1": {
47
+ "uid": "waffle1",
48
+ "type": "waffle-chart",
49
+ "title": "Vaccination Coverage",
50
+ "visualizationType": "TP5 Waffle",
51
+ "visualizationSubType": "linear",
52
+ "showPercent": true,
53
+ "showDenominator": false,
54
+ "valueDescription": "",
55
+ "content": "of the population is vaccinated against seasonal flu",
56
+ "subtext": "Based on 2024 CDC surveillance data across all age groups",
57
+ "dataColumn": "Vaccination Rate",
58
+ "dataFunction": "Mean (Average)",
59
+ "customDenom": false,
60
+ "dataDenom": "100",
61
+ "suffix": "%",
62
+ "roundToPlace": "1",
63
+ "theme": "theme-blue",
64
+ "shape": "square",
65
+ "visual": {
66
+ "whiteBackground": false
67
+ },
68
+ "showTitle": true,
69
+ "overallFontSize": "medium"
70
+ },
71
+ "waffle2": {
72
+ "uid": "waffle2",
73
+ "type": "waffle-chart",
74
+ "title": "Health Insurance Coverage Rate",
75
+ "visualizationType": "TP5 Waffle",
76
+ "visualizationSubType": "linear",
77
+ "showPercent": true,
78
+ "showDenominator": false,
79
+ "valueDescription": "",
80
+ "content": "completed recommended cancer screenings including mammography, colonoscopy, and cervical cancer screening",
81
+ "subtext": "",
82
+ "dataColumn": "Insured Rate",
83
+ "dataFunction": "Mean (Average)",
84
+ "customDenom": false,
85
+ "dataDenom": "100",
86
+ "suffix": "%",
87
+ "roundToPlace": "1",
88
+ "theme": "theme-teal",
89
+ "shape": "person",
90
+ "visual": {
91
+ "whiteBackground": false
92
+ },
93
+ "showTitle": true,
94
+ "overallFontSize": "medium"
95
+ },
96
+ "waffle3": {
97
+ "uid": "waffle3",
98
+ "type": "waffle-chart",
99
+ "title": "Cancer Screening Completion",
100
+ "visualizationType": "TP5 Waffle",
101
+ "visualizationSubType": "linear",
102
+ "showPercent": true,
103
+ "showDenominator": false,
104
+ "valueDescription": "",
105
+ "content": "completed recommended cancer screenings including mammography, colonoscopy, and cervical cancer screening",
106
+ "subtext": "Data from National Health Interview Survey 2024",
107
+ "dataColumn": "Screening Rate",
108
+ "dataFunction": "Mean (Average)",
109
+ "customDenom": false,
110
+ "dataDenom": "100",
111
+ "suffix": "%",
112
+ "roundToPlace": "1",
113
+ "theme": "theme-purple",
114
+ "shape": "circle",
115
+ "visual": {
116
+ "whiteBackground": false
117
+ },
118
+ "showTitle": true,
119
+ "overallFontSize": "medium"
120
+ },
121
+ "gauge1": {
122
+ "uid": "gauge1",
123
+ "type": "waffle-chart",
124
+ "title": "Vaccination Coverage",
125
+ "visualizationType": "TP5 Gauge",
126
+ "visualizationSubType": "linear",
127
+ "showPercent": true,
128
+ "showDenominator": false,
129
+ "valueDescription": "",
130
+ "content": "of the population is vaccinated against seasonal flu",
131
+ "subtext": "Based on 2024 CDC surveillance data across all age groups",
132
+ "dataColumn": "Vaccination Rate",
133
+ "dataFunction": "Mean (Average)",
134
+ "customDenom": false,
135
+ "dataDenom": "100",
136
+ "suffix": "%",
137
+ "roundToPlace": "1",
138
+ "theme": "theme-blue",
139
+ "gauge": {
140
+ "height": 35,
141
+ "width": "100%"
142
+ },
143
+ "visual": {
144
+ "whiteBackground": false
145
+ },
146
+ "showTitle": true,
147
+ "overallFontSize": "medium"
148
+ },
149
+ "gauge2": {
150
+ "uid": "gauge2",
151
+ "type": "waffle-chart",
152
+ "title": "Health Insurance Coverage Rate",
153
+ "visualizationType": "TP5 Gauge",
154
+ "visualizationSubType": "linear",
155
+ "showPercent": true,
156
+ "showDenominator": false,
157
+ "valueDescription": "",
158
+ "content": "",
159
+ "subtext": "",
160
+ "dataColumn": "Insured Rate",
161
+ "dataFunction": "Mean (Average)",
162
+ "customDenom": false,
163
+ "dataDenom": "100",
164
+ "suffix": "%",
165
+ "roundToPlace": "1",
166
+ "theme": "theme-teal",
167
+ "gauge": {
168
+ "height": 35,
169
+ "width": "100%"
170
+ },
171
+ "visual": {
172
+ "whiteBackground": false
173
+ },
174
+ "showTitle": true,
175
+ "overallFontSize": "medium"
176
+ },
177
+ "gauge3": {
178
+ "uid": "gauge3",
179
+ "type": "waffle-chart",
180
+ "title": "Cancer Screening Completion",
181
+ "visualizationType": "TP5 Gauge",
182
+ "visualizationSubType": "linear",
183
+ "showPercent": true,
184
+ "showDenominator": false,
185
+ "valueDescription": "",
186
+ "content": "completed recommended cancer screenings including mammography, colonoscopy, and cervical cancer screening",
187
+ "subtext": "Data from National Health Interview Survey 2024",
188
+ "dataColumn": "Screening Rate",
189
+ "dataFunction": "Mean (Average)",
190
+ "customDenom": false,
191
+ "dataDenom": "100",
192
+ "suffix": "%",
193
+ "roundToPlace": "1",
194
+ "theme": "theme-purple",
195
+ "gauge": {
196
+ "height": 35,
197
+ "width": "100%"
198
+ },
199
+ "visual": {
200
+ "whiteBackground": false
201
+ },
202
+ "showTitle": true,
203
+ "overallFontSize": "medium"
204
+ },
205
+ "bite1": {
206
+ "uid": "bite1",
207
+ "type": "data-bite",
208
+ "title": "Vaccination Coverage",
209
+ "biteStyle": "tp5",
210
+ "dataColumn": "Vaccination Rate",
211
+ "dataFunction": "Mean (Average)",
212
+ "biteBody": "of the population is vaccinated against seasonal flu",
213
+ "subtext": "Based on 2024 CDC surveillance data across all age groups",
214
+ "dataFormat": {
215
+ "roundToPlace": 1,
216
+ "commas": true,
217
+ "prefix": "",
218
+ "suffix": "%"
219
+ },
220
+ "theme": "theme-blue",
221
+ "visual": {
222
+ "hideBackgroundColor": false
223
+ }
224
+ },
225
+ "bite2": {
226
+ "uid": "bite2",
227
+ "type": "data-bite",
228
+ "title": "Health Insurance Coverage Rate",
229
+ "biteStyle": "tp5",
230
+ "dataColumn": "Insured Rate",
231
+ "dataFunction": "Mean (Average)",
232
+ "biteBody": "",
233
+ "subtext": "",
234
+ "dataFormat": {
235
+ "roundToPlace": 1,
236
+ "commas": true,
237
+ "prefix": "",
238
+ "suffix": "%"
239
+ },
240
+ "theme": "theme-teal",
241
+ "visual": {
242
+ "hideBackgroundColor": false
243
+ }
244
+ },
245
+ "bite3": {
246
+ "uid": "bite3",
247
+ "type": "data-bite",
248
+ "title": "Cancer Screening Completion",
249
+ "biteStyle": "tp5",
250
+ "dataColumn": "Screening Rate",
251
+ "dataFunction": "Mean (Average)",
252
+ "biteBody": "completed recommended cancer screenings including mammography, colonoscopy, and cervical cancer screening",
253
+ "subtext": "Data from National Health Interview Survey 2024",
254
+ "dataFormat": {
255
+ "roundToPlace": 1,
256
+ "commas": true,
257
+ "prefix": "",
258
+ "suffix": "%"
259
+ },
260
+ "theme": "theme-purple",
261
+ "visual": {
262
+ "hideBackgroundColor": false
263
+ }
264
+ }
265
+ }
266
+ }
267
+
@@ -11,6 +11,7 @@ import { MouseEventHandler } from 'react'
11
11
  import Loader from '@cdc/core/components/Loader'
12
12
  import _ from 'lodash'
13
13
  import { DROPDOWN_STYLES } from '@cdc/core/components/Filters/components/Dropdown'
14
+ import Tabs from '@cdc/core/components/Filters/components/Tabs'
14
15
 
15
16
  type DashboardFilterProps = {
16
17
  show: number[]
@@ -63,7 +64,12 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
63
64
  const urlFilterType = filter.type === 'urlfilter'
64
65
  const label = stripDuplicateLabelIncrement(filter.key || '')
65
66
 
66
- if (!urlFilterType && !filter.showDropdown && filter.filterStyle !== FILTER_STYLE.nestedDropdown)
67
+ if (
68
+ !urlFilterType &&
69
+ !filter.showDropdown &&
70
+ filter.filterStyle !== FILTER_STYLE.nestedDropdown &&
71
+ filter.filterStyle !== FILTER_STYLE.tabSimple
72
+ )
67
73
  return <React.Fragment key={`${filter.key}-filtersection-${filterIndex}-option`} />
68
74
  const values: JSX.Element[] = []
69
75
 
@@ -125,7 +131,10 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
125
131
  )
126
132
  }
127
133
 
128
- const formGroupClass = `form-group me-4 mb-1${loading ? ' loading-filter' : ''}`
134
+ const isTabSimple = filter.filterStyle === FILTER_STYLE.tabSimple
135
+ const formGroupClass = `form-group${isTabSimple ? '' : ' me-4'} mb-1${loading ? ' loading-filter' : ''}${
136
+ isTabSimple ? ' w-100' : ''
137
+ }`
129
138
  return (
130
139
  <div className={formGroupClass} key={`${filter.key}-filtersection-${filterIndex}`}>
131
140
  {label && (
@@ -133,7 +142,14 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
133
142
  {label}
134
143
  </label>
135
144
  )}
136
- {filter.filterStyle === FILTER_STYLE.multiSelect ? (
145
+ {filter.filterStyle === FILTER_STYLE.tabSimple ? (
146
+ <Tabs
147
+ filter={filter}
148
+ index={filterIndex}
149
+ changeFilterActive={(index, value) => handleOnChange(index, value)}
150
+ loading={loading}
151
+ />
152
+ ) : filter.filterStyle === FILTER_STYLE.multiSelect ? (
137
153
  <MultiSelect
138
154
  label={label}
139
155
  options={multiValues}
@@ -12,7 +12,7 @@ import Icon from '@cdc/core/components/ui/Icon'
12
12
  import FieldSetWrapper from '@cdc/core/components/EditorPanel/FieldSetWrapper'
13
13
  import FilterEditor from './components/FilterEditor'
14
14
  import { DashboardContext, DashboardDispatchContext } from '../../../DashboardContext'
15
- import _ from 'lodash'
15
+ import cloneDeep from 'lodash/cloneDeep'
16
16
  import { DashboardFilters } from '../../../types/DashboardFilters'
17
17
  import { SharedFilter } from '../../../types/SharedFilter'
18
18
  import { useGlobalContext } from '@cdc/core/components/GlobalContext'
@@ -52,9 +52,10 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
52
52
 
53
53
  const openControls = useState({})
54
54
  const [canAddExisting, setCanAddExisting] = useState(false)
55
+ const [isNestedDragHovered, setIsNestedDragHovered] = useState(false)
55
56
 
56
57
  const updateFilterProp = (prop: string, index: number, value) => {
57
- const newSharedFilters = _.cloneDeep(sharedFilters)
58
+ const newSharedFilters = cloneDeep(sharedFilters)
58
59
  const {
59
60
  apiEndpoint: oldEndpoint,
60
61
  valueSelector: oldValueSelector,
@@ -101,6 +102,9 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
101
102
  // changing a api filter and want to load the api data into the preview.
102
103
  // automatically dispatches SET_SHARED_FILTERS
103
104
  loadAPIFilters(newSharedFilters, {})
105
+ } else if (prop === 'defaultValue') {
106
+ newSharedFilters[index].active = value
107
+ dispatch({ type: 'SET_SHARED_FILTERS', payload: newSharedFilters })
104
108
  } else {
105
109
  handleSorting(newSharedFilters[index])
106
110
  dispatch({ type: 'SET_SHARED_FILTERS', payload: newSharedFilters })
@@ -108,7 +112,7 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
108
112
  }
109
113
 
110
114
  const toggleNestedQueryParameters = (index, checked: boolean) => {
111
- const newSharedFilters = _.cloneDeep(sharedFilters)
115
+ const newSharedFilters = cloneDeep(sharedFilters)
112
116
  const filter = newSharedFilters[index]
113
117
  const isUrlFilter = filter.type === 'urlfilter'
114
118
  const groupColumnName = isUrlFilter ? filter.apiFilter.valueSelector : filter.columnName
@@ -148,7 +152,7 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
148
152
  }
149
153
 
150
154
  const addNewFilter = () => {
151
- const _sharedFilters = _.cloneDeep(sharedFilters) || []
155
+ const _sharedFilters = cloneDeep(sharedFilters) || []
152
156
  const columnName = 'New Dashboard Filter ' + (_sharedFilters.length + 1)
153
157
  const newFilter = { key: columnName, showDropdown: true, values: [] } as SharedFilter
154
158
  dispatch({ type: 'SET_SHARED_FILTERS', payload: [..._sharedFilters, newFilter] })
@@ -255,6 +259,7 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
255
259
  key={filter.key + index}
256
260
  draggableId={`filter-${filter.key}-${index}`}
257
261
  index={filterIndex}
262
+ isDragDisabled={isNestedDragHovered}
258
263
  >
259
264
  {(provided, snapshot) => (
260
265
  <div
@@ -296,6 +301,7 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
296
301
  toggleNestedQueryParameters(index, checked)
297
302
  }}
298
303
  config={config}
304
+ onNestedDragAreaHover={setIsNestedDragHovered}
299
305
  />
300
306
  </FieldSetWrapper>
301
307
  </div>
@@ -16,7 +16,7 @@ const APIModal: React.FC<APIModalProps> = ({ filter, isNestedDropdown, updateAPI
16
16
  const [APISubGroupValueSelector, setAPISubGroupValueSelector] = useState(filter.apiFilter?.subgroupValueSelector)
17
17
  const [APISubGroupTextSelector, setAPISubGroupTextSelector] = useState(filter.apiFilter?.subgroupTextSelector)
18
18
  return (
19
- <fieldset className='mb-1 px-3 cdc-open-viz-module'>
19
+ <fieldset className='mb-1 px-3 cove-visualization'>
20
20
  <label className='d-block'>
21
21
  <span>API Endpoint: </span>
22
22
  <textarea
@@ -1,4 +1,3 @@
1
- import _ from 'lodash'
2
1
  import { getVizRowColumnLocator } from '../../../../helpers/getVizRowColumnLocator'
3
2
  import { Select, TextField } from '@cdc/core/components/EditorPanel/Inputs'
4
3
  import DataTransform from '@cdc/core/helpers/DataTransform'
@@ -27,6 +26,7 @@ type FilterEditorProps = {
27
26
  filterIndex: number
28
27
  updateFilterProp: (name: keyof SharedFilter, value: any) => void
29
28
  toggleNestedQueryParameters: (checked: boolean) => void
29
+ onNestedDragAreaHover?: (isHovering: boolean) => void
30
30
  }
31
31
 
32
32
  const FilterEditor: React.FC<FilterEditorProps> = ({
@@ -34,7 +34,8 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
34
34
  filterIndex,
35
35
  config,
36
36
  updateFilterProp,
37
- toggleNestedQueryParameters
37
+ toggleNestedQueryParameters,
38
+ onNestedDragAreaHover
38
39
  }) => {
39
40
  const [columns, setColumns] = useState<string[]>([])
40
41
  const [dataFiltersLoading, setDataFiltersLoading] = useState(false)
@@ -103,7 +104,7 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
103
104
  let _dataSet = config.datasets[dataKey]
104
105
  if (!_dataSet.data && _dataSet.dataUrl) {
105
106
  setDataFiltersLoading(true)
106
- let data = await fetchRemoteData(_dataSet.dataUrl)
107
+ let data = (await fetchRemoteData(_dataSet.dataUrl)).data
107
108
  if (_dataSet.dataDescription && data && data.length > 0) {
108
109
  try {
109
110
  data = transform.autoStandardize(data)
@@ -546,6 +547,7 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
546
547
  values.splice(index2, 0, removed)
547
548
  updateFilterProp('orderedValues', values)
548
549
  }}
550
+ onNestedDragAreaHover={onNestedDragAreaHover}
549
551
  />
550
552
  )}
551
553
 
@@ -569,6 +571,7 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
569
571
  }}
570
572
  isDashboard={true}
571
573
  config={config}
574
+ onNestedDragAreaHover={onNestedDragAreaHover}
572
575
  />
573
576
  <label>
574
577
  <input
@@ -1,6 +1,7 @@
1
1
  import { DashboardConfig } from '../../../../types/DashboardConfig'
2
2
  import { SharedFilter } from '../../../../types/SharedFilter'
3
- import _ from 'lodash'
3
+ import cloneDeep from 'lodash/cloneDeep'
4
+ import uniq from 'lodash/uniq'
4
5
  import { SubGrouping, OrderBy } from '@cdc/core/types/VizFilter'
5
6
  import { TextField, Select } from '@cdc/core/components/EditorPanel/Inputs'
6
7
  import { handleSorting } from '@cdc/core/components/Filters/helpers/handleSorting'
@@ -12,13 +13,15 @@ type NestedDropDownEditorDashboardProps = {
12
13
  filter: SharedFilter
13
14
  isDashboard: boolean
14
15
  updateFilterProp: Function
16
+ onNestedDragAreaHover?: (isHovering: boolean) => void
15
17
  }
16
18
 
17
19
  const NestedDropDownDashboard: React.FC<NestedDropDownEditorDashboardProps> = ({
18
20
  filter,
19
21
  config,
20
22
  isDashboard = false,
21
- updateFilterProp
23
+ updateFilterProp,
24
+ onNestedDragAreaHover
22
25
  }) => {
23
26
  const subGrouping = filter?.subGrouping
24
27
 
@@ -70,7 +73,7 @@ const NestedDropDownDashboard: React.FC<NestedDropDownEditorDashboardProps> = ({
70
73
  const order = subGrouping?.order || 'asc'
71
74
 
72
75
  const valuesLookup = filter.values.reduce((acc, groupName) => {
73
- const rawValues: string[] = _.uniq(
76
+ const rawValues: string[] = uniq(
74
77
  config.datasets[selectedOptionDatasetName].data
75
78
  .map(d => {
76
79
  return d[filter.columnName] === groupName ? d[newColumnName] : ''
@@ -102,7 +105,7 @@ const NestedDropDownDashboard: React.FC<NestedDropDownEditorDashboardProps> = ({
102
105
  // Handle group order change (asc/desc/cust)
103
106
  const handleGroupingOrderBy = (order: OrderBy) => {
104
107
  const groupSortObject = {
105
- values: _.cloneDeep(filter.values),
108
+ values: cloneDeep(filter.values),
106
109
  order
107
110
  }
108
111
  const { values: newOrderedValues } = handleSorting(groupSortObject)
@@ -126,7 +129,7 @@ const NestedDropDownDashboard: React.FC<NestedDropDownEditorDashboardProps> = ({
126
129
  const handleGroupingCustomOrder = (sourceIndex: number, destinationIndex: number) => {
127
130
  if (sourceIndex === undefined || destinationIndex === undefined || sourceIndex === destinationIndex) return
128
131
 
129
- const orderedValues = _.cloneDeep(filter.orderedValues || filter.values)
132
+ const orderedValues = cloneDeep(filter.orderedValues || filter.values)
130
133
  const [movedItem] = orderedValues.splice(sourceIndex, 1)
131
134
  orderedValues.splice(destinationIndex, 0, movedItem)
132
135
 
@@ -141,7 +144,7 @@ const NestedDropDownDashboard: React.FC<NestedDropDownEditorDashboardProps> = ({
141
144
  const handleSubGroupingOrderBy = (order: OrderBy) => {
142
145
  const newValuesLookup = Object.keys(subGrouping.valuesLookup).reduce((acc, groupName) => {
143
146
  const subGroup = subGrouping.valuesLookup[groupName]
144
- const { values: sortedValues } = handleSorting({ values: _.cloneDeep(subGroup.values), order })
147
+ const { values: sortedValues } = handleSorting({ values: cloneDeep(subGroup.values), order })
145
148
 
146
149
  acc[groupName] = {
147
150
  values: sortedValues,
@@ -168,11 +171,11 @@ const NestedDropDownDashboard: React.FC<NestedDropDownEditorDashboardProps> = ({
168
171
  ) => {
169
172
  if (sourceIndex === undefined || destinationIndex === undefined || sourceIndex === destinationIndex) return
170
173
 
171
- const updatedGroupOrderedValues = _.cloneDeep(currentOrderedValues)
174
+ const updatedGroupOrderedValues = cloneDeep(currentOrderedValues)
172
175
  const [movedItem] = updatedGroupOrderedValues.splice(sourceIndex, 1)
173
176
  updatedGroupOrderedValues.splice(destinationIndex, 0, movedItem)
174
177
 
175
- const newSubGrouping = _.cloneDeep(subGrouping)
178
+ const newSubGrouping = cloneDeep(subGrouping)
176
179
  newSubGrouping.valuesLookup[groupName].values = updatedGroupOrderedValues
177
180
  newSubGrouping.valuesLookup[groupName].orderedValues = updatedGroupOrderedValues
178
181
  newSubGrouping.order = 'cust'
@@ -270,6 +273,7 @@ const NestedDropDownDashboard: React.FC<NestedDropDownEditorDashboardProps> = ({
270
273
  <FilterOrder
271
274
  orderedValues={filter.orderedValues || filter.values}
272
275
  handleFilterOrder={handleGroupingCustomOrder}
276
+ onNestedDragAreaHover={onNestedDragAreaHover}
273
277
  />
274
278
  )}
275
279
  </div>
@@ -298,6 +302,7 @@ const NestedDropDownDashboard: React.FC<NestedDropDownEditorDashboardProps> = ({
298
302
  handleFilterOrder={(sourceIndex, destinationIndex) => {
299
303
  handleSubGroupingCustomOrder(sourceIndex, destinationIndex, orderedSubGroupValues, groupName)
300
304
  }}
305
+ onNestedDragAreaHover={onNestedDragAreaHover}
301
306
  />
302
307
  </div>
303
308
  )