@cdc/dashboard 4.25.8 → 4.25.11

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 (88) hide show
  1. package/dist/{cdcdashboard-fce76882.es.js → cdcdashboard-BnB1QM5d.es.js} +6 -13
  2. package/dist/{cdcdashboard-c55ac1ea.es.js → cdcdashboard-D6CG2-Hb.es.js} +5 -12
  3. package/dist/{cdcdashboard-31a33da1.es.js → cdcdashboard-MXgURbdZ.es.js} +6 -13
  4. package/dist/{cdcdashboard-1a1724a1.es.js → cdcdashboard-dgT_1dIT.es.js} +136 -151
  5. package/dist/cdcdashboard.js +80040 -75976
  6. package/examples/api-test/categories.json +18 -0
  7. package/examples/api-test/chart-data.json +602 -0
  8. package/examples/api-test/topics.json +47 -0
  9. package/examples/api-test/years.json +22 -0
  10. package/examples/markup-axis-label.json +4167 -0
  11. package/examples/private/DEV-10538.json +407 -0
  12. package/examples/private/DEV-11405.json +39112 -0
  13. package/examples/private/big-dashboard.json +39112 -0
  14. package/examples/private/brfs-2.json +1532 -0
  15. package/examples/private/brfs.json +2128 -2138
  16. package/examples/private/clade-2.json +430 -0
  17. package/examples/private/delete.json +32919 -0
  18. package/examples/private/diabetes.json +5582 -0
  19. package/examples/private/example-2.json +49796 -0
  20. package/examples/private/group-legend-test.json +328 -0
  21. package/examples/private/map.json +1211 -0
  22. package/examples/private/markup-footer/burden_toolkit_mortality_diabetes_attributable_deaths_data.csv +14041 -0
  23. package/examples/private/markup-footer/burden_toolkit_mortality_diabetes_attributable_deaths_per_100000_data.csv +14041 -0
  24. package/examples/private/markup-footer/burden_toolkit_mortality_qaly_data.csv +18721 -0
  25. package/examples/private/markup-footer/burden_toolkit_mortality_yll_data.csv +18721 -0
  26. package/examples/private/markup-footer/mortality-deaths-footnotes-age.csv +3 -0
  27. package/examples/private/markup-variables.json +1451 -0
  28. package/examples/private/markup.json +5471 -0
  29. package/examples/private/mpox.json +38128 -0
  30. package/examples/private/north-dakota.json +1132 -0
  31. package/examples/private/ophdst.json +38754 -0
  32. package/examples/private/pedro.json +1 -0
  33. package/examples/private/pivot.json +683 -0
  34. package/examples/private/reset.json +32920 -0
  35. package/examples/private/sewershed.json +435 -0
  36. package/examples/private/tobacco.json +1938 -0
  37. package/examples/test-api-filter-reset.json +132 -0
  38. package/index.html +2 -2
  39. package/package.json +16 -10
  40. package/src/CdcDashboard.tsx +1 -3
  41. package/src/CdcDashboardComponent.tsx +34 -16
  42. package/src/DashboardContext.tsx +5 -1
  43. package/src/_stories/Dashboard.API.stories.tsx +62 -0
  44. package/src/_stories/Dashboard.stories.tsx +492 -472
  45. package/src/_stories/_mock/api/cessation.json +1 -0
  46. package/src/_stories/_mock/api/data-explorer.json +1 -0
  47. package/src/_stories/_mock/api/explore-by-location.json +1 -0
  48. package/src/_stories/_mock/api/explore-by-topic.json +1 -0
  49. package/src/_stories/_mock/api/legislation.json +1 -0
  50. package/src/_stories/_mock/api/oral-health-data.json +1 -0
  51. package/src/_stories/_mock/custom-order-new-values.json +116 -0
  52. package/src/components/CollapsibleVisualizationRow.tsx +1 -1
  53. package/src/components/DashboardFilters/DashboardFilters.tsx +34 -23
  54. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +29 -12
  55. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +81 -112
  56. package/src/components/DashboardFilters/DashboardFiltersEditor/components/NestedDropDownDashboard.tsx +82 -52
  57. package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +130 -31
  58. package/src/components/DashboardFilters/_stories/DashboardFilters.stories.tsx +80 -21
  59. package/src/components/DataDesignerModal.tsx +227 -210
  60. package/src/components/Header/Header.tsx +13 -12
  61. package/src/components/Toggle/Toggle.tsx +48 -47
  62. package/src/components/VisualizationRow.tsx +13 -6
  63. package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +2 -0
  64. package/src/components/Widget/Widget.tsx +47 -18
  65. package/src/helpers/addValuesToDashboardFilters.ts +111 -60
  66. package/src/helpers/apiFilterHelpers.ts +190 -166
  67. package/src/helpers/filterData.ts +52 -7
  68. package/src/helpers/filterResetHelpers.ts +102 -0
  69. package/src/helpers/formatConfigBeforeSave.ts +137 -0
  70. package/src/helpers/getVizConfig.ts +36 -18
  71. package/src/helpers/loadAPIFilters.ts +109 -99
  72. package/src/helpers/reloadURLHelpers.ts +1 -1
  73. package/src/helpers/tests/filterResetHelpers.test.ts +532 -0
  74. package/src/helpers/tests/formatConfigBeforeSave.test.ts +69 -0
  75. package/src/index.tsx +1 -1
  76. package/src/scss/editor-panel.scss +3 -431
  77. package/src/scss/grid.scss +7 -5
  78. package/src/scss/main.scss +1 -24
  79. package/src/store/errorMessage/errorMessage.reducer.ts +1 -1
  80. package/src/types/DashboardFilters.ts +9 -8
  81. package/src/types/InitialState.ts +12 -12
  82. package/vite.config.js +1 -1
  83. package/vitest.config.ts +16 -0
  84. package/src/coreStyles_dashboard.scss +0 -3
  85. package/src/helpers/getAutoLoadVisualization.ts +0 -11
  86. package/src/scss/mixins.scss +0 -47
  87. package/src/scss/variables.scss +0 -5
  88. /package/dist/{cdcdashboard-548642e6.es.js → cdcdashboard-Ct2SB0vL.es.js} +0 -0
@@ -18,6 +18,7 @@ type DashboardFilterProps = {
18
18
  showSubmit: boolean
19
19
  applyFilters: MouseEventHandler<HTMLButtonElement>
20
20
  applyFiltersButtonText?: string
21
+ handleReset?: MouseEventHandler<HTMLButtonElement>
21
22
  }
22
23
 
23
24
  const DashboardFilters: React.FC<DashboardFilterProps> = ({
@@ -27,7 +28,8 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
27
28
  handleOnChange,
28
29
  showSubmit,
29
30
  applyFilters,
30
- applyFiltersButtonText
31
+ applyFiltersButtonText,
32
+ handleReset
31
33
  }) => {
32
34
  const nullVal = (filter: SharedFilter) => {
33
35
  const val = filter.queuedActive || filter.active
@@ -76,11 +78,6 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
76
78
  ]
77
79
  )
78
80
 
79
- const activeSubGroupValue = _.get(
80
- filter?.subGrouping?.valuesLookup,
81
- [filter?.active as string, 'values', 0],
82
- null // Default to null if the path is invalid
83
- )
84
81
  if (_key && apiFilterDropdowns[_key]) {
85
82
  // URL Filter
86
83
  if (filter.filterStyle !== FILTER_STYLE.nestedDropdown) {
@@ -120,8 +117,8 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
120
117
  }
121
118
 
122
119
  const isDisabled = !values.length
123
- // push reset label only if it does not includes in filter values options
124
- if (filter.resetLabel && !filter.values.includes(filter.resetLabel)) {
120
+ // push reset label only if it does not includes in filter values options
121
+ if (filter.resetLabel && !filter.values.includes(filter.resetLabel) && !_key) {
125
122
  values.unshift(
126
123
  <option key={`${filter.resetLabel}-option`} value={filter.resetLabel}>
127
124
  {filter.resetLabel}
@@ -150,7 +147,7 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
150
147
  ) : filter.filterStyle === FILTER_STYLE.nestedDropdown ? (
151
148
  <NestedDropdown
152
149
  activeGroup={(filter.queuedActive?.[0] || filter.active) as string}
153
- activeSubGroup={_key ? filter.queuedActive?.[1] || filter.subGrouping?.active : activeSubGroupValue}
150
+ activeSubGroup={(filter.queuedActive?.[1] || filter.subGrouping?.active) as string}
154
151
  filterIndex={filterIndex}
155
152
  options={_key ? getNestedDropdownOptions(apiFilterDropdowns[_key]) : nestedOptions}
156
153
  listLabel={label}
@@ -170,7 +167,14 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
170
167
  disabled={loading || isDisabled}
171
168
  >
172
169
  {loading && <option value='Loading...'>Loading...</option>}
173
- {nullVal(filter) && (
170
+ {/* For API filters, show placeholder when no value is selected */}
171
+ {_key && nullVal(filter) && (
172
+ <option key={`reset-label`} value=''>
173
+ {filter.resetLabel || '- Select One -'}
174
+ </option>
175
+ )}
176
+ {/* For non-API filters or when no value is selected, show empty option */}
177
+ {!_key && nullVal(filter) && (
174
178
  <option key={`select`} value=''>
175
179
  {filter.resetLabel || '- Select -'}
176
180
  </option>
@@ -184,19 +188,26 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
184
188
  )
185
189
  })}
186
190
  {showSubmit && (
187
- <button
188
- className='btn btn-primary mb-1'
189
- onClick={applyFilters}
190
- disabled={show.some(filterIndex => {
191
- const emptyFilterValues = [undefined, '', '- Select -']
192
- return (
193
- emptyFilterValues.includes(sharedFilters[filterIndex].queuedActive) &&
194
- emptyFilterValues.includes(sharedFilters[filterIndex].active)
195
- )
196
- })}
197
- >
198
- {applyFiltersButtonText || 'GO!'}
199
- </button>
191
+ <>
192
+ <button
193
+ className='btn btn-primary mb-1 me-2'
194
+ onClick={applyFilters}
195
+ disabled={show.some(filterIndex => {
196
+ const emptyFilterValues = [undefined, '', '- Select -']
197
+ return (
198
+ emptyFilterValues.includes(sharedFilters[filterIndex].queuedActive) &&
199
+ emptyFilterValues.includes(sharedFilters[filterIndex].active)
200
+ )
201
+ })}
202
+ >
203
+ {applyFiltersButtonText || 'GO!'}
204
+ </button>
205
+ {handleReset && (
206
+ <button className='btn btn-link mb-1' onClick={handleReset}>
207
+ Clear Filters
208
+ </button>
209
+ )}
210
+ </>
200
211
  )}
201
212
  </form>
202
213
  )
@@ -43,9 +43,10 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
43
43
  return config.dashboard.sharedFilters
44
44
  ?.map<[number, string]>(({ key }, i) => [i, key])
45
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
- ))
46
+ .map(([filterIndex, filterName]) => ({
47
+ value: String(filterIndex),
48
+ label: `${filterIndex} - ${filterName}`
49
+ }))
49
50
  }, [config.visualizations, vizConfig.uid])
50
51
 
51
52
  const openControls = useState({})
@@ -189,6 +190,27 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
189
190
  }
190
191
  />
191
192
  )}
193
+ {vizConfig.filterBehavior === 'Apply Button' && (
194
+ <CheckBox
195
+ label='Show Clear Filters Button'
196
+ value={vizConfig.showClearButton ?? true}
197
+ updateField={(_section, _subsection, _key, value) => {
198
+ updateConfig({ ...vizConfig, showClearButton: value })
199
+ }}
200
+ tooltip={
201
+ <Tooltip style={{ textTransform: 'none' }}>
202
+ <Tooltip.Target>
203
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
204
+ </Tooltip.Target>
205
+ <Tooltip.Content>
206
+ <p>
207
+ When enabled, displays a "Clear Filters" button that allows users to reset all filter selections.
208
+ </p>
209
+ </Tooltip.Content>
210
+ </Tooltip>
211
+ }
212
+ />
213
+ )}
192
214
  </AccordionItemPanel>
193
215
  </AccordionItem>
194
216
 
@@ -254,8 +276,10 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
254
276
  </Tooltip.Content>
255
277
  </Tooltip>
256
278
  </span>
257
- <select
279
+ <Select
280
+ label=''
258
281
  value={''}
282
+ options={[{ value: '', label: 'Select' }, ...(existingOptions || [])]}
259
283
  onChange={e => {
260
284
  updateConfig({
261
285
  ...vizConfig,
@@ -263,14 +287,7 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
263
287
  })
264
288
  setCanAddExisting(false)
265
289
  }}
266
- >
267
- {[
268
- <option key='select' value=''>
269
- Select
270
- </option>,
271
- ...existingOptions
272
- ]}
273
- </select>
290
+ />
274
291
  </label>
275
292
  ) : (
276
293
  <button onClick={() => setCanAddExisting(true)} className='btn btn-primary full-width mt-2'>
@@ -100,7 +100,7 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
100
100
  if (!_dataSet.data && _dataSet.dataUrl) {
101
101
  setDataFiltersLoading(true)
102
102
  let data = await fetchRemoteData(_dataSet.dataUrl)
103
- if (_dataSet.dataDescription) {
103
+ if (_dataSet.dataDescription && data && data.length > 0) {
104
104
  try {
105
105
  data = transform.autoStandardize(data)
106
106
  data = transform.developerStandardize(data, _dataSet.dataDescription)
@@ -110,6 +110,9 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
110
110
  } finally {
111
111
  _dataSet.data = data
112
112
  }
113
+ } else if (data) {
114
+ // If no dataDescription but we have data, store it directly
115
+ _dataSet.data = data
113
116
  }
114
117
  }
115
118
 
@@ -181,33 +184,25 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
181
184
  return (
182
185
  <>
183
186
  {dataFiltersLoading && <Loading />}
184
- <label>
185
- <span className='edit-label column-heading'>Filter Type: </span>
186
- <select
187
- defaultValue={filter.type || ''}
188
- onChange={e => selectFilterType(e.target.value)}
189
- disabled={!!filter.type}
190
- >
191
- <option value=''>- Select Option -</option>
192
- <option value='urlfilter'>URL</option>
193
- <option value='datafilter'>Data</option>
194
- </select>
195
- </label>
187
+ <Select
188
+ label='Filter Type'
189
+ value={filter.type || ''}
190
+ options={[
191
+ { value: '', label: '- Select Option -' },
192
+ { value: 'urlfilter', label: 'URL' },
193
+ { value: 'datafilter', label: 'Data' }
194
+ ]}
195
+ onChange={e => selectFilterType(e.target.value)}
196
+ disabled={!!filter.type}
197
+ />
196
198
  {filter.type !== undefined && (
197
199
  <>
198
- <label>
199
- <span className='edit-label column-heading'>Filter Style: </span>
200
- <select
201
- value={filter.filterStyle || FILTER_STYLE.dropdown}
202
- onChange={e => updateFilterProp('filterStyle', e.target.value)}
203
- >
204
- {filterStyles.map(dataKey => (
205
- <option value={dataKey} key={`filter-style-select-item-${dataKey}`}>
206
- {dataKey}
207
- </option>
208
- ))}
209
- </select>
210
- </label>
200
+ <Select
201
+ label='Filter Style'
202
+ value={filter.filterStyle || FILTER_STYLE.dropdown}
203
+ options={filterStyles}
204
+ onChange={e => updateFilterProp('filterStyle', e.target.value)}
205
+ />
211
206
  {filter.filterStyle === FILTER_STYLE.dropdown && (
212
207
  <label>
213
208
  <span className='me-1'>Show Dropdown</span>
@@ -251,41 +246,31 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
251
246
  <>
252
247
  {!hasDashboardApplyBehavior(config.visualizations) && (
253
248
  <>
254
- <label>
255
- <span className='edit-label column-heading'>URL to Filter: </span>
256
- <select
257
- defaultValue={filter.datasetKey || ''}
258
- onChange={e => updateFilterProp('datasetKey', e.target.value)}
259
- >
260
- <option value=''>- Select Option -</option>
261
- {Object.keys(config.datasets).map(datasetKey => {
262
- if (config.datasets[datasetKey].dataUrl) {
263
- return (
264
- <option key={datasetKey} value={datasetKey}>
265
- {config.datasets[datasetKey].dataUrl}
266
- </option>
267
- )
268
- }
269
- return null
270
- })}
271
- </select>
272
- </label>
249
+ <Select
250
+ label='URL to Filter'
251
+ value={filter.datasetKey || ''}
252
+ options={[
253
+ { value: '', label: '- Select Option -' },
254
+ ...Object.keys(config.datasets)
255
+ .filter(datasetKey => config.datasets[datasetKey].dataUrl)
256
+ .map(datasetKey => ({
257
+ value: datasetKey,
258
+ label: config.datasets[datasetKey].dataUrl
259
+ }))
260
+ ]}
261
+ onChange={e => updateFilterProp('datasetKey', e.target.value)}
262
+ />
273
263
 
274
- <label>
275
- <span className='edit-label column-heading'>Filter By: </span>
276
- <select
277
- defaultValue={filter.filterBy || ''}
278
- onChange={e => updateFilterProp('filterBy', e.target.value)}
279
- >
280
- <option value=''>- Select Option -</option>
281
- <option key={'query-string'} value={'Query String'}>
282
- Query String
283
- </option>
284
- <option key={'file-name'} value={'File Name'}>
285
- File Name
286
- </option>
287
- </select>
288
- </label>
264
+ <Select
265
+ label='Filter By'
266
+ value={filter.filterBy || ''}
267
+ options={[
268
+ { value: '', label: '- Select Option -' },
269
+ { value: 'Query String', label: 'Query String' },
270
+ { value: 'File Name', label: 'File Name' }
271
+ ]}
272
+ onChange={e => updateFilterProp('filterBy', e.target.value)}
273
+ />
289
274
  {filter.filterBy === 'File Name' && (
290
275
  <>
291
276
  <TextField
@@ -304,9 +289,16 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
304
289
  }
305
290
  />
306
291
 
307
- <label>
308
- <span className='edit-label column-heading'>
309
- White Space Replacments
292
+ <Select
293
+ label='White Space Replacments'
294
+ value={filter.whitespaceReplacement || 'Keep Spaces'}
295
+ options={[
296
+ { value: 'Remove Spaces', label: 'Remove Spaces' },
297
+ { value: 'Replace With Underscore', label: 'Replace With Underscore' },
298
+ { value: 'Keep Spaces', label: 'Keep Spaces' }
299
+ ]}
300
+ onChange={e => updateFilterProp('whitespaceReplacement', e.target.value)}
301
+ tooltip={
310
302
  <Tooltip style={{ textTransform: 'none' }}>
311
303
  <Tooltip.Target>
312
304
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
@@ -315,22 +307,8 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
315
307
  <p>{`Set how whitespace characters will be handled in the file request`}</p>
316
308
  </Tooltip.Content>
317
309
  </Tooltip>
318
- </span>
319
- <select
320
- defaultValue={filter.whitespaceReplacement || 'Keep Spaces'}
321
- onChange={e => updateFilterProp('whitespaceReplacement', e.target.value)}
322
- >
323
- <option key={'remove-spaces'} value={'Remove Spaces'}>
324
- Remove Spaces
325
- </option>
326
- <option key={'replace-with-underscore'} value={'Replace With Underscore'}>
327
- Replace With Underscore
328
- </option>
329
- <option key={'keep-spaces'} value={'Keep Spaces'}>
330
- Keep Spaces
331
- </option>
332
- </select>
333
- </label>
310
+ }
311
+ />
334
312
  </>
335
313
  )}
336
314
  </>
@@ -504,22 +482,17 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
504
482
  <>
505
483
  {filter.filterStyle !== FILTER_STYLE.nestedDropdown ? (
506
484
  <>
507
- <label>
508
- <span className='edit-label column-heading'>Filter: </span>
509
- <select
510
- value={filter.columnName}
511
- onChange={e => {
512
- updateFilterProp('columnName', e.target.value)
513
- }}
514
- >
515
- <option value=''>- Select Option -</option>
516
- {columns.map(dataKey => (
517
- <option value={dataKey} key={`filter-column-select-item-${dataKey}`}>
518
- {dataKey}
519
- </option>
520
- ))}
521
- </select>
522
- </label>
485
+ <Select
486
+ label='Filter'
487
+ value={filter.columnName || ''}
488
+ options={[
489
+ { value: '', label: '- Select Option -' },
490
+ ...columns.map(col => ({ value: col, label: col }))
491
+ ]}
492
+ onChange={e => {
493
+ updateFilterProp('columnName', e.target.value)
494
+ }}
495
+ />
523
496
 
524
497
  <Select
525
498
  value={filter.defaultValue}
@@ -644,23 +617,19 @@ const FilterEditor: React.FC<FilterEditorProps> = ({
644
617
  updateField={(_section, _subSection, _key, value) => updateFilterProp('resetLabel', value)}
645
618
  />
646
619
 
647
- <label>
648
- <span className='edit-label column-heading'>Parent Filter: </span>
649
- <select
650
- value={filter.parents || []}
651
- onChange={e => {
652
- updateFilterProp('parents', e.target.value)
653
- }}
654
- >
655
- <option value=''>Select a filter</option>
656
- {config.dashboard.sharedFilters &&
657
- config.dashboard.sharedFilters.map(sharedFilter => {
658
- if (sharedFilter.key !== filter.key) {
659
- return <option key={sharedFilter.key}>{sharedFilter.key}</option>
660
- }
661
- })}
662
- </select>
663
- </label>
620
+ <Select
621
+ label='Parent Filter'
622
+ value={filter.parents || ''}
623
+ options={[
624
+ { value: '', label: 'Select a filter' },
625
+ ...(config.dashboard.sharedFilters || [])
626
+ .filter(sharedFilter => sharedFilter.key !== filter.key)
627
+ .map(sharedFilter => ({ value: sharedFilter.key, label: sharedFilter.key }))
628
+ ]}
629
+ onChange={e => {
630
+ updateFilterProp('parents', e.target.value)
631
+ }}
632
+ />
664
633
 
665
634
  {!isNestedDropdown && (
666
635
  <TextField
@@ -2,7 +2,7 @@ import { DashboardConfig } from '../../../../types/DashboardConfig'
2
2
  import { SharedFilter } from '../../../../types/SharedFilter'
3
3
  import _ from 'lodash'
4
4
  import { SubGrouping } from '@cdc/core/types/VizFilter'
5
- import { TextField } from '@cdc/core/components/EditorPanel/Inputs'
5
+ import { TextField, Select } from '@cdc/core/components/EditorPanel/Inputs'
6
6
 
7
7
  type NestedDropDownEditorDashboardProps = {
8
8
  config: DashboardConfig
@@ -47,16 +47,24 @@ const NestedDropDownDashboard: React.FC<NestedDropDownEditorDashboardProps> = ({
47
47
  })
48
48
  }
49
49
 
50
- const handleFitlerGroupColumnNameChange = selectedOption => {
51
- const selectedOptionDatasetName = selectedOption.selectedOptions[0].dataset.set
52
- const newColumnName = selectedOption.value
50
+ const handleFitlerGroupColumnNameChange = (value: string) => {
51
+ if (!value) {
52
+ updateFilterProp('columnName', '')
53
+ updateFilterProp('defaultValue', '')
54
+ return
55
+ }
56
+ const [newColumnName, selectedOptionDatasetName] = value.split('|')
53
57
  updateFilterProp('columnName', newColumnName)
58
+ updateFilterProp('defaultValue', '') // Reset default value when column changes
54
59
  populateSubGroupingOptions(selectedOptionDatasetName, newColumnName)
55
60
  }
56
61
 
57
- const handleSubGroupColumnNameChange = selectedOption => {
58
- const selectedOptionDatasetName = selectedOption.selectedOptions[0].dataset.set
59
- const newColumnName = selectedOption.value
62
+ const handleSubGroupColumnNameChange = (value: string) => {
63
+ if (!value) {
64
+ updateFilterProp('subGrouping', { ...subGrouping, columnName: '', valuesLookup: {}, defaultValue: '' })
65
+ return
66
+ }
67
+ const [newColumnName, selectedOptionDatasetName] = value.split('|')
60
68
 
61
69
  const valuesLookup = filter.values.reduce((acc, groupName) => {
62
70
  const values: string[] = _.uniq(
@@ -77,7 +85,8 @@ const NestedDropDownDashboard: React.FC<NestedDropDownEditorDashboardProps> = ({
77
85
  const newSubGrouping: SubGrouping = {
78
86
  ...subGrouping,
79
87
  columnName: newColumnName,
80
- valuesLookup
88
+ valuesLookup,
89
+ defaultValue: '' // Reset default value when column changes
81
90
  }
82
91
 
83
92
  updateFilterProp('subGrouping', newSubGrouping)
@@ -92,51 +101,72 @@ const NestedDropDownDashboard: React.FC<NestedDropDownEditorDashboardProps> = ({
92
101
  updateField={(_section, _subSection, _key, value) => updateFilterProp('key', value)}
93
102
  />
94
103
  )}
95
- <label>
96
- <div className='edit-label column-heading mt-2'>
97
- Filter Grouping
98
- <span></span>
99
- </div>
100
- <select value={filter.columnName} onChange={e => handleFitlerGroupColumnNameChange(e.target)}>
101
- <option value=''>- Select Option -</option>
102
- {columnNameOptionsInDataset?.map(option => (
103
- <option
104
- value={option.columnName}
105
- data-set={option.datasetKey}
106
- key={`filter_${option.datasetKey}_${option.columnName} `}
107
- >
108
- {option.columnName}
109
- </option>
110
- ))}
111
- </select>
112
- </label>
113
- <label>
114
- <div className='edit-label column-heading mt-2'>
115
- Filter SubGrouping
116
- <span></span>
117
- </div>
118
- <select
119
- value={subGrouping?.columnName ?? ''}
120
- onChange={e => {
121
- handleSubGroupColumnNameChange(e.target)
104
+ <Select
105
+ label='Filter Grouping'
106
+ value={
107
+ filter.columnName
108
+ ? `${filter.columnName}|${
109
+ columnNameOptionsInDataset.find(opt => opt.columnName === filter.columnName)?.datasetKey || ''
110
+ }`
111
+ : ''
112
+ }
113
+ options={[
114
+ { value: '', label: '- Select Option -' },
115
+ ...columnNameOptionsInDataset.map(option => ({
116
+ value: `${option.columnName}|${option.datasetKey}`,
117
+ label: option.columnName
118
+ }))
119
+ ]}
120
+ onChange={e => handleFitlerGroupColumnNameChange(e.target.value)}
121
+ />
122
+ <Select
123
+ label='Filter SubGrouping'
124
+ value={
125
+ subGrouping?.columnName
126
+ ? `${subGrouping.columnName}|${
127
+ columnNameOptionsInDataset.find(opt => opt.columnName === subGrouping.columnName)?.datasetKey || ''
128
+ }`
129
+ : ''
130
+ }
131
+ options={[
132
+ { value: '', label: '- Select Option -' },
133
+ ...columnNameOptionsInDataset
134
+ .filter(option => option.columnName !== filter.columnName)
135
+ .map(option => ({
136
+ value: `${option.columnName}|${option.datasetKey}`,
137
+ label: option.columnName
138
+ }))
139
+ ]}
140
+ onChange={e => handleSubGroupColumnNameChange(e.target.value)}
141
+ />
142
+
143
+ {/* Default Value for Main Group */}
144
+ {filter.columnName && filter.values && filter.values.length > 0 && (
145
+ <Select
146
+ value={filter.defaultValue}
147
+ options={filter.values}
148
+ updateField={(_section, _subSection, _key, value) => updateFilterProp('defaultValue', value)}
149
+ label={'Group Default Value'}
150
+ initial={'Select'}
151
+ />
152
+ )}
153
+
154
+ {/* Default Value for Sub Group */}
155
+ {subGrouping?.columnName && (filter.defaultValue || filter.active) && subGrouping.valuesLookup && (
156
+ <Select
157
+ value={subGrouping.defaultValue}
158
+ options={(() => {
159
+ const groupKey = filter.defaultValue || (Array.isArray(filter.active) ? filter.active[0] : filter.active)
160
+ return subGrouping.valuesLookup[groupKey as string]?.values || []
161
+ })()}
162
+ updateField={(_section, _subSection, _key, value) => {
163
+ const newSubGrouping = { ...subGrouping, defaultValue: value }
164
+ updateFilterProp('subGrouping', newSubGrouping)
122
165
  }}
123
- >
124
- <option value=''>- Select Option -</option>
125
- {columnNameOptionsInDataset.map(option => {
126
- if (option.columnName !== filter.columnName) {
127
- return (
128
- <option
129
- value={option.columnName}
130
- data-set={option.datasetKey}
131
- key={`subFilter_${option.datasetKey}_${option.columnName} `}
132
- >
133
- {option.columnName}
134
- </option>
135
- )
136
- }
137
- })}
138
- </select>
139
- </label>
166
+ label={'Sub Group Default Value'}
167
+ initial={'Select'}
168
+ />
169
+ )}
140
170
  </div>
141
171
  )
142
172
  }