@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
@@ -0,0 +1,137 @@
1
+ import Footnotes from '@cdc/core/types/Footnotes'
2
+ import { AnyVisualization, Visualization } from '@cdc/core/types/Visualization'
3
+ import { DashboardConfig } from '../types/DashboardConfig'
4
+ import { removeDashboardFilter } from './removeDashboardFilter'
5
+ import _ from 'lodash'
6
+ import cloneConfig from '@cdc/core/helpers/cloneConfig'
7
+
8
+ const cleanDashboardFootnotes = (config: DashboardConfig) => {
9
+ if (config.visualizations) {
10
+ Object.keys(config.visualizations).forEach(vizKey => {
11
+ const viz = config.visualizations[vizKey] as any
12
+ if (viz.footnotes) {
13
+ delete viz.footnotes.data
14
+ delete viz.footnotes.formattedData
15
+ }
16
+ })
17
+ }
18
+ }
19
+
20
+ const cleanDashboardData = (config: DashboardConfig) => {
21
+ if (config.datasets) {
22
+ Object.keys(config.datasets).forEach(datasetKey => {
23
+ delete config.datasets[datasetKey].formattedData
24
+ if (config.datasets[datasetKey].dataUrl) {
25
+ delete config.datasets[datasetKey].data
26
+ }
27
+ })
28
+ }
29
+ if (config.visualizations) {
30
+ Object.keys(config.visualizations).forEach(vizKey => {
31
+ config.visualizations[vizKey] = _.omit(config.visualizations[vizKey], [
32
+ 'runtime',
33
+ 'formattedData',
34
+ 'data',
35
+ 'editing',
36
+ 'originalFormattedData'
37
+ ]) as any
38
+ })
39
+ }
40
+ if (config.rows) {
41
+ config.rows.forEach((row, i) => {
42
+ if (row.dataKey) {
43
+ config.rows[i] = _.omit(row, ['data', 'formattedData'])
44
+ }
45
+ })
46
+ }
47
+ }
48
+
49
+ export const cleanSharedFilters = (config: DashboardConfig) => {
50
+ if (config.dashboard?.sharedFilters) {
51
+ const recursiveRemoveFilters = (sharedFilters, visualizations: Record<string, AnyVisualization>) => {
52
+ const usedFilters = _.uniq(
53
+ Object.values(visualizations).reduce((acc, viz) => {
54
+ if (viz.type === 'dashboardFilters') {
55
+ acc = acc.concat(viz.sharedFilterIndexes)
56
+ }
57
+ return acc
58
+ }, [])
59
+ )
60
+ for (let index = 0; index < sharedFilters.length; index++) {
61
+ const filter = sharedFilters[index]
62
+ if (!usedFilters.includes(index)) {
63
+ const [newSharedFilters, newVisualizations] = removeDashboardFilter(
64
+ index,
65
+ config.dashboard.sharedFilters,
66
+ config.visualizations
67
+ )
68
+ config.dashboard.sharedFilters = newSharedFilters
69
+ config.visualizations = newVisualizations
70
+ recursiveRemoveFilters(newSharedFilters, newVisualizations)
71
+ break
72
+ } else {
73
+ delete config.dashboard.sharedFilters[index].active
74
+ if (filter.subGrouping) delete config.dashboard.sharedFilters[index].subGrouping.active
75
+ if (filter.type === 'urlfilter') {
76
+ delete config.dashboard.sharedFilters[index].values
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ recursiveRemoveFilters(config.dashboard.sharedFilters, config.visualizations)
83
+ }
84
+ }
85
+
86
+ const cleanVisualizationFilters = (config: DashboardConfig) => {
87
+ if (config.visualizations) {
88
+ Object.keys(config.visualizations).forEach(vizKey => {
89
+ const viz = config.visualizations[vizKey] as any
90
+ const vizFilters = viz.filters || []
91
+ vizFilters.forEach((_filter, index) => {
92
+ delete viz.filters[index].active
93
+ delete viz.filters[index].values
94
+ })
95
+ })
96
+ }
97
+ }
98
+
99
+ const removeRuntimeDataURLs = (config: DashboardConfig) => {
100
+ if (config.datasets) {
101
+ Object.keys(config.datasets).forEach(datasetKey => {
102
+ delete config.datasets[datasetKey].runtimeDataUrl
103
+ })
104
+ }
105
+ }
106
+
107
+ export const stripConfig = configToStrip => {
108
+ const strippedConfig = cloneConfig(configToStrip)
109
+ if (strippedConfig.type === 'dashboard') {
110
+ if (strippedConfig.multiDashboards) {
111
+ strippedConfig.multiDashboards.forEach((multiDashboard, i) => {
112
+ cleanDashboardData(strippedConfig.multiDashboards[i])
113
+ cleanSharedFilters(strippedConfig.multiDashboards[i])
114
+ cleanDashboardFootnotes(strippedConfig.multiDashboards[i])
115
+ cleanVisualizationFilters(strippedConfig.multiDashboards[i])
116
+ })
117
+ delete strippedConfig.dashboard
118
+ delete strippedConfig.rows
119
+ delete strippedConfig.visualizations
120
+ delete strippedConfig.label
121
+ }
122
+ delete strippedConfig.activeDashboard
123
+ cleanDashboardData(strippedConfig)
124
+ cleanSharedFilters(strippedConfig)
125
+ cleanDashboardFootnotes(strippedConfig)
126
+ cleanVisualizationFilters(strippedConfig)
127
+ removeRuntimeDataURLs(strippedConfig)
128
+ } else {
129
+ delete strippedConfig.runtime
130
+ delete strippedConfig.formattedData
131
+ if (strippedConfig.dataUrl) {
132
+ delete strippedConfig.data
133
+ }
134
+ }
135
+
136
+ return strippedConfig
137
+ }
@@ -1,4 +1,5 @@
1
1
  import _ from 'lodash'
2
+ import cloneConfig from '@cdc/core/helpers/cloneConfig'
2
3
  import { MultiDashboardConfig } from '../types/MultiDashboard'
3
4
  import DataTransform from '@cdc/core/helpers/DataTransform'
4
5
  import { getApplicableFilters } from './getFilteredData'
@@ -7,7 +8,7 @@ import { AnyVisualization } from '@cdc/core/types/Visualization'
7
8
 
8
9
  const transform = new DataTransform()
9
10
 
10
- export const getFootnotesVizConfig = (
11
+ const getFootnotesVizConfig = (
11
12
  visualizationConfig: AnyVisualization,
12
13
  rowNumber: number,
13
14
  config: MultiDashboardConfig,
@@ -23,7 +24,7 @@ export const getFootnotesVizConfig = (
23
24
  const sharedFilters = config.dashboard.sharedFilters
24
25
  const matchingFilters = sharedFilters.filter(f => f.usedBy?.includes(visualizationKey))
25
26
 
26
- if (matchingFilters.length) {
27
+ if (matchingFilters.length && visualizationConfig.footnotes.data) {
27
28
  visualizationConfig.footnotes.data = filterData(matchingFilters, data)
28
29
  } else {
29
30
  if (visualizationConfig.footnotes.data) {
@@ -44,7 +45,7 @@ export const getVizConfig = (
44
45
  multiVizColumn?: string
45
46
  ): AnyVisualization => {
46
47
  if (rowNumber === undefined) return {} as AnyVisualization
47
- const visualizationConfig = _.cloneDeep(config.visualizations[visualizationKey])
48
+ const visualizationConfig = cloneConfig(config.visualizations[visualizationKey])
48
49
  const rowData = config.rows[rowNumber]
49
50
  if (visualizationConfig.footnotes?.dataKey) {
50
51
  visualizationConfig.footnotes.data = config.datasets[visualizationConfig.footnotes.dataKey]?.data
@@ -54,21 +55,36 @@ export const getVizConfig = (
54
55
  Object.assign(visualizationConfig, _.pick(rowData, ['dataKey', 'dataDescription', 'formattedData', 'data']))
55
56
  }
56
57
 
57
- if (visualizationConfig.table && config.dashboard.sharedFilters.length) {
58
- // Download CSV button needs to know to include shared filter columns
59
- const sharedFilterColumns = config.dashboard.sharedFilters.reduce((acc, filter) => {
60
- if (!filter.usedBy?.length || filter.usedBy?.includes(visualizationKey)) {
61
- const apiFilter = filter.apiFilter
62
- const colName = apiFilter?.textSelector || apiFilter?.valueSelector || filter.columnName
63
- acc.push(colName)
64
- const subGrouping =
65
- apiFilter?.subgroupTextSelector || apiFilter?.subgroupValueSelector || filter.subGrouping?.columnName
66
- if (subGrouping) {
67
- acc.push(subGrouping)
68
- }
58
+ const sharedFilterColumns = config.dashboard.sharedFilters.reduce((acc, filter) => {
59
+ if (!filter.usedBy?.length || filter.usedBy?.includes(visualizationKey)) {
60
+ const apiFilter = filter.apiFilter
61
+ const colName = apiFilter?.textSelector || apiFilter?.valueSelector || filter.columnName
62
+ acc.push(colName)
63
+ const subGrouping =
64
+ apiFilter?.subgroupTextSelector || apiFilter?.subgroupValueSelector || filter.subGrouping?.columnName
65
+ if (subGrouping) {
66
+ acc.push(subGrouping)
69
67
  }
70
- return acc
71
- }, [])
68
+ }
69
+ return acc
70
+ }, [])
71
+
72
+ // Collect active dashboard filters for markup variable processing
73
+ // This allows markup variables to filter even when the viz isn't in usedBy
74
+ const activeDashboardFilters = config.dashboard.sharedFilters
75
+ .filter(filter => filter.active !== undefined && filter.active !== null && filter.active !== '')
76
+ .map(filter => ({
77
+ columnName: filter.columnName,
78
+ active: filter.active,
79
+ values: filter.values || []
80
+ }))
81
+
82
+ if (activeDashboardFilters.length > 0) {
83
+ visualizationConfig.dashboardFilters = activeDashboardFilters
84
+ }
85
+
86
+ // Download CSV button needs to know to include shared filter columns
87
+ if (visualizationConfig.table && config.dashboard.sharedFilters.length) {
72
88
  visualizationConfig.table.sharedFilterColumns = sharedFilterColumns
73
89
  }
74
90
 
@@ -82,7 +98,9 @@ export const getVizConfig = (
82
98
  }
83
99
  } else {
84
100
  const dataKey = visualizationConfig.dataKey || 'backwards-compatibility'
85
- visualizationConfig.data = data[dataKey] || []
101
+ // Markup-includes need data even when shared filters exist (for markup variables)
102
+ const shouldClearData = sharedFilterColumns.length && visualizationConfig.type !== 'markup-include'
103
+ visualizationConfig.data = shouldClearData ? [] : data[dataKey] || []
86
104
  if (visualizationConfig.formattedData) {
87
105
  visualizationConfig.formattedData =
88
106
  transform.developerStandardize(visualizationConfig.data, visualizationConfig.dataDescription) ||
@@ -1,99 +1,109 @@
1
- import _ from 'lodash'
2
- import { APIFilterDropdowns } from '../components/DashboardFilters'
3
- import { SharedFilter } from '../types/SharedFilter'
4
- import * as apiFilterHelpers from './apiFilterHelpers'
5
- import { APIFilter } from '../types/APIFilter'
6
- import { getParentParams, notAllParentsSelected } from './apiFilterHelpers'
7
-
8
- export const loadAPIFiltersFactory = (
9
- dispatch: Function,
10
- dispatchErrorMessages: Function,
11
- setAPIFilterDropdowns: Function,
12
- autoLoadFilterIndexes: number[]
13
- ) => {
14
- const loadAPIFilters = (
15
- sharedFilters: SharedFilter[],
16
- dropdowns: APIFilterDropdowns,
17
- loadAll?: boolean,
18
- recursiveLimit = 50
19
- ): Promise<SharedFilter[]> => {
20
- if (!sharedFilters) return
21
- const allIndexes = sharedFilters.map((_, index) => index)
22
- const _autoLoadFilterIndexes = loadAll ? allIndexes : autoLoadFilterIndexes
23
- sharedFilters = sharedFilters.map((filter, index) =>
24
- apiFilterHelpers.setAutoLoadDefaultValue(
25
- index,
26
- dropdowns[filter.apiFilter?.apiEndpoint],
27
- sharedFilters,
28
- _autoLoadFilterIndexes
29
- )
30
- )
31
- const sharedAPIFilters = sharedFilters.filter(f => f.apiFilter)
32
- const filterLookup = new Map(sharedAPIFilters.map(filter => [filter.apiFilter.apiEndpoint, filter.apiFilter]))
33
- const toFetch = apiFilterHelpers.getToFetch(sharedFilters, dropdowns)
34
- const loadingDropdowns = Object.values(toFetch).reduce(
35
- (acc, [dropdownsKey]) => ({ ...acc, [dropdownsKey]: null }),
36
- {}
37
- )
38
- setAPIFilterDropdowns(currentState => {
39
- return { ...currentState, ...loadingDropdowns }
40
- })
41
- const newDropdowns = _.cloneDeep(dropdowns)
42
- return Promise.all(
43
- Object.keys(toFetch).map(
44
- endpoint =>
45
- new Promise<{ error: boolean }>(resolve => {
46
- fetch(endpoint)
47
- .then(resp => resp.json())
48
- .then(data => {
49
- if (!Array.isArray(data)) {
50
- console.error('COVE only supports response data in the shape Array<Object>')
51
- }
52
- const [_key, index] = toFetch[endpoint]
53
- const apiFilter = filterLookup.get(_key) as APIFilter
54
- const _filterValues = apiFilterHelpers.getFilterValues(data, apiFilter)
55
-
56
- newDropdowns[_key] = _filterValues
57
- const newDefaultSelectedFilter = apiFilterHelpers.setAutoLoadDefaultValue(
58
- index,
59
- _filterValues,
60
- sharedFilters,
61
- _autoLoadFilterIndexes
62
- )
63
- sharedFilters[index] = newDefaultSelectedFilter
64
- })
65
- .catch(() => {
66
- dispatchErrorMessages({
67
- type: 'ADD_ERROR_MESSAGE',
68
- payload: 'There was a problem returning data. Please try again.'
69
- })
70
- resolve({ error: true })
71
- })
72
- .finally(() => {
73
- resolve({ error: false })
74
- })
75
- })
76
- )
77
- ).then(responses => {
78
- const hasError = responses.some(({ error }) => error)
79
- const toLoad = sharedFilters.reduce((acc, curr, index) => {
80
- // the filter is autoloading and it hasn't finished yet
81
- if (_autoLoadFilterIndexes.includes(index) && !curr.active) {
82
- if (notAllParentsSelected(getParentParams(curr, sharedFilters))) {
83
- return acc
84
- }
85
- return [...acc, index]
86
- }
87
- return acc
88
- }, [])
89
- if (hasError || !toLoad.length || recursiveLimit === 0) {
90
- setAPIFilterDropdowns(newDropdowns)
91
- dispatch({ type: 'SET_SHARED_FILTERS', payload: sharedFilters })
92
- return sharedFilters
93
- } else {
94
- return loadAPIFilters(sharedFilters, newDropdowns, loadAll, recursiveLimit - 1)
95
- }
96
- })
97
- }
98
- return loadAPIFilters
99
- }
1
+ import _ from 'lodash'
2
+ import { APIFilterDropdowns } from '../components/DashboardFilters'
3
+ import { SharedFilter } from '../types/SharedFilter'
4
+ import * as apiFilterHelpers from './apiFilterHelpers'
5
+ import { APIFilter } from '../types/APIFilter'
6
+ import { getParentParams, notAllParentsSelected } from './apiFilterHelpers'
7
+
8
+ export const loadAPIFiltersFactory = (
9
+ dispatch: Function,
10
+ dispatchErrorMessages: Function,
11
+ setAPIFilterDropdowns: Function,
12
+ autoLoadFilterIndexes: number[]
13
+ ) => {
14
+ const loadAPIFilters = (
15
+ sharedFilters: SharedFilter[],
16
+ dropdowns: APIFilterDropdowns,
17
+ loadAll?: boolean,
18
+ recursiveLimit = 50,
19
+ isStale?: () => boolean
20
+ ): Promise<SharedFilter[]> => {
21
+ if (!sharedFilters) return
22
+ const allIndexes = sharedFilters.map((_, index) => index)
23
+ const _autoLoadFilterIndexes = loadAll ? allIndexes : autoLoadFilterIndexes
24
+ sharedFilters = sharedFilters.map((filter, index) => {
25
+ // For data filters (no API endpoint), return unchanged to preserve user selections
26
+ if (!filter.apiFilter?.apiEndpoint) {
27
+ return filter
28
+ }
29
+ return apiFilterHelpers.setAutoLoadDefaultValue(
30
+ index,
31
+ dropdowns[filter.apiFilter.apiEndpoint],
32
+ sharedFilters,
33
+ _autoLoadFilterIndexes
34
+ )
35
+ })
36
+ const sharedAPIFilters = sharedFilters.filter(f => f.apiFilter)
37
+ const filterLookup = new Map(sharedAPIFilters.map(filter => [filter.apiFilter.apiEndpoint, filter.apiFilter]))
38
+ const toFetch = apiFilterHelpers.getToFetch(sharedFilters, dropdowns)
39
+ const loadingDropdowns = Object.values(toFetch).reduce(
40
+ (acc, [dropdownsKey]) => ({ ...acc, [dropdownsKey]: null }),
41
+ {}
42
+ )
43
+ setAPIFilterDropdowns(currentState => {
44
+ return { ...currentState, ...loadingDropdowns }
45
+ })
46
+ const newDropdowns = _.cloneDeep(dropdowns)
47
+ return Promise.all(
48
+ Object.keys(toFetch).map(
49
+ endpoint =>
50
+ new Promise<{ error: boolean }>(resolve => {
51
+ fetch(endpoint)
52
+ .then(resp => resp.json())
53
+ .then(data => {
54
+ if (!Array.isArray(data)) {
55
+ console.error('COVE only supports response data in the shape Array<Object>')
56
+ }
57
+ const [_key, index] = toFetch[endpoint]
58
+ const apiFilter = filterLookup.get(_key) as APIFilter
59
+ const _filterValues = apiFilterHelpers.getFilterValues(data, apiFilter)
60
+
61
+ newDropdowns[_key] = _filterValues
62
+ const newDefaultSelectedFilter = apiFilterHelpers.setAutoLoadDefaultValue(
63
+ index,
64
+ _filterValues,
65
+ sharedFilters,
66
+ _autoLoadFilterIndexes
67
+ )
68
+ sharedFilters[index] = newDefaultSelectedFilter
69
+ })
70
+ .catch(() => {
71
+ dispatchErrorMessages({
72
+ type: 'ADD_ERROR_MESSAGE',
73
+ payload: 'There was a problem returning data. Please try again.'
74
+ })
75
+ resolve({ error: true })
76
+ })
77
+ .finally(() => {
78
+ resolve({ error: false })
79
+ })
80
+ })
81
+ )
82
+ ).then(responses => {
83
+ const hasError = responses.some(({ error }) => error)
84
+ const toLoad = sharedFilters.reduce((acc, curr, index) => {
85
+ // the filter is autoloading and it hasn't finished yet
86
+ if (_autoLoadFilterIndexes.includes(index) && !curr.active) {
87
+ if (notAllParentsSelected(getParentParams(curr, sharedFilters))) {
88
+ return acc
89
+ }
90
+ return [...acc, index]
91
+ }
92
+ return acc
93
+ }, [])
94
+ if (hasError || !toLoad.length || recursiveLimit === 0) {
95
+ // Check if this operation is stale before dispatching
96
+ if (isStale && isStale()) {
97
+ // Operation is stale (filters were cleared), skip dispatch
98
+ return sharedFilters
99
+ }
100
+ setAPIFilterDropdowns(newDropdowns)
101
+ dispatch({ type: 'SET_SHARED_FILTERS', payload: sharedFilters })
102
+ return sharedFilters
103
+ } else {
104
+ return loadAPIFilters(sharedFilters, newDropdowns, loadAll, recursiveLimit - 1, isStale)
105
+ }
106
+ })
107
+ }
108
+ return loadAPIFilters
109
+ }
@@ -103,7 +103,7 @@ export const getVisualizationsWithFormattedData = (visualizations: Record<string
103
103
  acc[vizKey].formattedData = newData[dataKey]
104
104
  }
105
105
  return acc
106
- }, _.cloneDeep(visualizations))
106
+ }, visualizations)
107
107
  }
108
108
 
109
109
  export const filterUsedByDataUrl = (