@cdc/dashboard 4.25.11 → 4.26.2

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 (77) hide show
  1. package/Dynamic_Data.md +66 -0
  2. package/dist/cdcdashboard-8NmHlKRI.es.js +15 -0
  3. package/dist/cdcdashboard-BPoPzKPz.es.js +6 -0
  4. package/dist/cdcdashboard-Cf9_fbQf.es.js +6 -0
  5. package/dist/{cdcdashboard-dgT_1dIT.es.js → cdcdashboard-DQ00cQCm.es.js} +1 -20
  6. package/dist/cdcdashboard-jiQQPkty.es.js +6 -0
  7. package/dist/cdcdashboard.js +83537 -86913
  8. package/examples/api-dashboard-data.json +272 -0
  9. package/examples/api-dashboard-years.json +11 -0
  10. package/examples/api-geographies-data.json +11 -0
  11. package/examples/default.json +522 -133
  12. package/examples/nested-dropdown.json +6985 -0
  13. package/examples/private/abc.json +467 -0
  14. package/examples/private/cat-y.json +1235 -0
  15. package/examples/private/chronic-dash.json +1584 -0
  16. package/examples/private/dash.json +12696 -0
  17. package/examples/private/map-issue.json +2260 -0
  18. package/examples/private/mpinc-state-reports.json +2260 -0
  19. package/examples/private/npcr.json +1 -0
  20. package/examples/private/nwss/rsv.json +1240 -0
  21. package/examples/private/simple-dash.json +490 -0
  22. package/examples/private/test-dash.json +0 -0
  23. package/examples/private/test.json +125407 -0
  24. package/examples/private/test123.json +491 -0
  25. package/examples/private/timeline-data.json +4994 -0
  26. package/examples/private/timeline.json +1708 -0
  27. package/examples/test-api-filter-reset.json +8 -4
  28. package/examples/test-dashboard-simple.json +503 -0
  29. package/examples/tp5-gauges.json +196 -0
  30. package/examples/tp5-test.json +266 -0
  31. package/index.html +1 -30
  32. package/package.json +39 -40
  33. package/src/CdcDashboardComponent.tsx +18 -5
  34. package/src/_stories/Dashboard.DataSetup.stories.tsx +204 -0
  35. package/src/_stories/Dashboard.stories.tsx +407 -1
  36. package/src/_stories/_mock/dashboard-line-chart-angles.json +1030 -0
  37. package/src/_stories/_mock/filter-cascade.json +3350 -0
  38. package/src/_stories/_mock/gallery-data-bite-dashboard.json +3500 -0
  39. package/src/_stories/_mock/nested-parent-child-filters.json +392 -0
  40. package/src/_stories/_mock/parent-child-filters.json +233 -0
  41. package/src/_stories/_mock/tp5-test.json +267 -0
  42. package/src/components/DashboardFilters/DashboardFilters.tsx +20 -11
  43. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +92 -38
  44. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +56 -30
  45. package/src/components/DashboardFilters/DashboardFiltersEditor/components/NestedDropDownDashboard.tsx +151 -10
  46. package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +11 -7
  47. package/src/components/DataDesignerModal.tsx +6 -1
  48. package/src/components/Header/Header.tsx +51 -20
  49. package/src/components/VisualizationRow.tsx +76 -5
  50. package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +2 -20
  51. package/src/components/Widget/Widget.tsx +1 -1
  52. package/src/data/initial-state.js +1 -0
  53. package/src/helpers/addValuesToDashboardFilters.ts +30 -31
  54. package/src/helpers/apiFilterHelpers.ts +28 -32
  55. package/src/helpers/changeFilterActive.ts +67 -65
  56. package/src/helpers/formatConfigBeforeSave.ts +6 -5
  57. package/src/helpers/getUpdateConfig.ts +91 -91
  58. package/src/helpers/tests/addValuesToDashboardFilters.test.ts +141 -44
  59. package/src/helpers/tests/apiFilterHelpers.test.ts +523 -420
  60. package/src/helpers/tests/updatesChildFilters.test.ts +53 -22
  61. package/src/helpers/updateChildFilters.ts +50 -27
  62. package/src/scss/main.scss +144 -1
  63. package/src/test/CdcDashboard.test.jsx +9 -4
  64. package/src/types/Dashboard.ts +1 -0
  65. package/src/types/FilterStyles.ts +8 -7
  66. package/src/types/SharedFilter.ts +13 -0
  67. package/vite.config.js +7 -1
  68. package/LICENSE +0 -201
  69. package/dist/cdcdashboard-BnB1QM5d.es.js +0 -361528
  70. package/dist/cdcdashboard-Ct2SB0vL.es.js +0 -231049
  71. package/dist/cdcdashboard-D6CG2-Hb.es.js +0 -39377
  72. package/dist/cdcdashboard-MXgURbdZ.es.js +0 -39194
  73. package/examples/private/DEV-10538.json +0 -407
  74. package/examples/private/DEV-11072.json +0 -7591
  75. package/examples/private/DEV-11405.json +0 -39112
  76. package/examples/private/delete.json +0 -32919
  77. package/examples/private/pedro.json +0 -1
@@ -1,5 +1,5 @@
1
1
  import _ from 'lodash'
2
- import { getQueryStringFilterValue } from '@cdc/core/helpers/queryStringUtils'
2
+ import { getQueryStringFilterValue, isFilterHiddenByQuery } from '@cdc/core/helpers/queryStringUtils'
3
3
  import { SharedFilter } from '../types/SharedFilter'
4
4
  import { handleSorting } from '@cdc/core/components/Filters'
5
5
  import { mergeCustomOrderValues } from '@cdc/core/helpers/mergeCustomOrderValues'
@@ -39,7 +39,11 @@ export const addValuesToDashboardFilters = (
39
39
  if (filtersToSkip.includes(index)) return filter
40
40
  if (filter.type === 'urlfilter') return filter
41
41
  const filterCopy = _.cloneDeep(filter)
42
- const filterValues = generateValuesForFilter(getSelector(filter), data)
42
+
43
+ // Only generate values from data if not pre-configured
44
+ const hasPreConfiguredValues = filter.values && filter.values.length > 0
45
+ const filterValues = hasPreConfiguredValues ? filter.values : generateValuesForFilter(getSelector(filter), data)
46
+
43
47
  filterCopy.values = filterValues
44
48
 
45
49
  // Merge new values with existing custom order (fixes DEV-11740 & DEV-11376)
@@ -54,32 +58,20 @@ export const addValuesToDashboardFilters = (
54
58
  const active: string[] = Array.isArray(filterCopy.active) ? filterCopy.active : [filterCopy.active]
55
59
  filterCopy.active = active.filter(val => defaultValues.includes(val))
56
60
  } else {
57
- // Preserve existing active value if it's valid in the new filter values
58
- const currentActive = filterCopy.active as string
59
- const isResetLabelValue = currentActive && currentActive === filterCopy.resetLabel
60
- const isCurrentActiveValid = currentActive && (filterValues.includes(currentActive) || isResetLabelValue)
61
-
62
- // Check if this is an intentional clear (empty string, but not undefined during initial load)
63
- const isIntentionalClear = currentActive === ''
64
-
65
- // Priority: defaultValue > valid current active > reset label > first value
61
+ // Use defaultValue if set, otherwise keep existing active or use first value
66
62
  if (filterCopy.defaultValue) {
67
- // If defaultValue is explicitly set, always use it
68
63
  filterCopy.active = filterCopy.defaultValue
69
- } else if (isCurrentActiveValid) {
70
- // Keep the current active value if valid
71
- filterCopy.active = currentActive
72
- } else if (isIntentionalClear) {
73
- // Don't override intentional clears
74
- filterCopy.active = currentActive
75
- } else {
76
- // Set to reset label or first value
77
- const defaultValue = filterCopy.resetLabel || filterCopy.values[0]
78
- filterCopy.active = defaultValue
64
+ } else if (!filterCopy.active) {
65
+ filterCopy.active = filterCopy.resetLabel || filterCopy.values[0]
79
66
  }
80
67
  }
81
68
  }
82
69
 
70
+ // Check if filter should be hidden by query parameter
71
+ if (isFilterHiddenByQuery(filterCopy)) {
72
+ filterCopy.showDropdown = false
73
+ }
74
+
83
75
  // Handle nested dropdown subGrouping.active property
84
76
  if (filterCopy.subGrouping && filterCopy.subGrouping.valuesLookup) {
85
77
  const groupName = filterCopy.active as string
@@ -89,17 +81,24 @@ export const addValuesToDashboardFilters = (
89
81
  }
90
82
  const queryStringFilterValue = getQueryStringFilterValue(subGroupingFilter)
91
83
  const groupActive = groupName || filterCopy.values[0]
92
- const defaultSubValue = filterCopy.subGrouping.valuesLookup[groupActive as string]?.values[0]
84
+ const currentGroupValues = filterCopy.subGrouping.valuesLookup[groupActive as string]?.values || []
85
+ const defaultSubValue = currentGroupValues[0]
93
86
 
94
- // Priority order: query string > existing active > configured default > first available value
95
- let activeValue = queryStringFilterValue || filterCopy.subGrouping.active
87
+ // Priority order: query string > configured default > existing active > first available value
88
+ let activeValue: string | undefined
96
89
 
97
- // If we have a configured default value and it exists in the current group's options, use it
98
- if (!activeValue && filterCopy.subGrouping.defaultValue) {
99
- const currentGroupValues = filterCopy.subGrouping.valuesLookup[groupActive as string]?.values || []
100
- if (currentGroupValues.includes(filterCopy.subGrouping.defaultValue)) {
101
- activeValue = filterCopy.subGrouping.defaultValue
102
- }
90
+ if (queryStringFilterValue && currentGroupValues.includes(queryStringFilterValue)) {
91
+ // 1. Query string parameter takes highest priority (only if valid for the current group)
92
+ activeValue = queryStringFilterValue
93
+ } else if (
94
+ filterCopy.subGrouping.defaultValue &&
95
+ currentGroupValues.includes(filterCopy.subGrouping.defaultValue)
96
+ ) {
97
+ // 2. Use configured defaultValue if it exists and is valid for the current group
98
+ activeValue = filterCopy.subGrouping.defaultValue
99
+ } else if (filterCopy.subGrouping.active && currentGroupValues.includes(filterCopy.subGrouping.active)) {
100
+ // 3. Keep existing active value if it's valid for the current group
101
+ activeValue = filterCopy.subGrouping.active
103
102
  }
104
103
 
105
104
  filterCopy.subGrouping.active = activeValue || defaultSubValue
@@ -119,35 +119,31 @@ export const getToFetch = (
119
119
  }
120
120
 
121
121
  export const setActiveNestedDropdown = (dropdownOptions, sharedFilter) => {
122
- const defaultQueryParamValue = getQueryParam(sharedFilter?.setByQueryParameter)
123
- const defaultValue = dropdownOptions[0]?.value
124
- const subDefaultValue = dropdownOptions[0]?.subOptions[0].value
125
- const subDefaultQueryParamValue = getQueryParam(sharedFilter?.subGrouping.setByQueryParameter)
126
- if (!sharedFilter.active) {
127
- sharedFilter.active = defaultQueryParamValue || defaultValue
128
- sharedFilter.subGrouping.active = subDefaultQueryParamValue || subDefaultValue
129
- } else {
130
- const currentOption = dropdownOptions.find(option => option.value === sharedFilter.active)
131
- sharedFilter.active = currentOption ? currentOption.value : defaultValue
132
- if (currentOption) {
133
- const currentSubOption = currentOption.subOptions.find(option => option.value === sharedFilter.subGrouping.active)
134
- sharedFilter.subGrouping.active = currentSubOption?.value || subDefaultValue
135
- } else {
136
- sharedFilter.subGrouping.active = subDefaultValue
137
- }
138
- }
122
+ const queryValue = getQueryParam(sharedFilter?.setByQueryParameter)
123
+ const subQueryValue = getQueryParam(sharedFilter?.subGrouping?.setByQueryParameter)
124
+
125
+ // Priority: query string > configured defaultValue > existing active (if valid) > first option
126
+ // Note: use loose equality here to match values across possible string/number differences
127
+ const validActive = dropdownOptions.find(option => option.value == sharedFilter.active)
128
+ sharedFilter.active =
129
+ queryValue || sharedFilter.defaultValue || (validActive ? sharedFilter.active : dropdownOptions[0]?.value)
130
+
131
+ const options = dropdownOptions.find(option => option.value == sharedFilter.active)?.subOptions || []
132
+ const validSubActive = options.find(o => o.value == sharedFilter.subGrouping?.active)
133
+ sharedFilter.subGrouping.active =
134
+ subQueryValue ||
135
+ sharedFilter.subGrouping?.defaultValue ||
136
+ (validSubActive ? sharedFilter.subGrouping.active : options[0]?.value)
139
137
  }
140
138
 
141
139
  export const setActiveMultiDropdown = (dropdownOptions, sharedFilter) => {
142
- const defaultQueryParamValue = getQueryParam(sharedFilter?.setByQueryParameter)
143
- const multiDefaultQueryParamValue = Array.isArray(defaultQueryParamValue)
144
- ? defaultQueryParamValue
145
- : defaultQueryParamValue?.split(',')
146
- const multiDefaultValue = defaultQueryParamValue ? multiDefaultQueryParamValue : [dropdownOptions[0]?.value]
140
+ const queryValue = getQueryParam(sharedFilter?.setByQueryParameter)
141
+ const queryValues = Array.isArray(queryValue) ? queryValue : queryValue?.split(',')
142
+ const defaultValues = queryValue ? queryValues : [dropdownOptions[0]?.value]
147
143
  const currentOption = (Array.isArray(sharedFilter.active) ? sharedFilter.active : []).filter(activeVal =>
148
144
  dropdownOptions.find(option => option.value === activeVal)
149
145
  )
150
- sharedFilter.active = currentOption.length ? currentOption : multiDefaultValue
146
+ sharedFilter.active = currentOption.length ? currentOption : defaultValues
151
147
  }
152
148
 
153
149
  export const setAutoLoadDefaultValue = (
@@ -158,20 +154,20 @@ export const setAutoLoadDefaultValue = (
158
154
  ): SharedFilter => {
159
155
  const sharedFiltersCopy = _.cloneDeep(sharedFilters)
160
156
  const sharedFilter = _.cloneDeep(sharedFiltersCopy[sharedFilterIndex])
161
- const defaultQueryParamValue = getQueryParam(sharedFilter?.setByQueryParameter)
162
- const hasQueryParameter = sharedFilter.setByQueryParameter ? defaultQueryParamValue !== undefined : false
157
+ const queryValue = getQueryParam(sharedFilter?.setByQueryParameter)
158
+ const hasQuery = sharedFilter.setByQueryParameter ? queryValue !== undefined : false
163
159
  if (!autoLoadFilterIndexes.length || !dropdownOptions?.length) {
164
- if (hasQueryParameter && sharedFilter.apiFilter) {
160
+ if (hasQuery && sharedFilter.apiFilter) {
165
161
  const subQueryValue = getQueryParam(sharedFilter.subGrouping?.setByQueryParameter)
166
- const isNestedDropdown = subQueryValue !== undefined
167
- sharedFilter.queuedActive = isNestedDropdown ? [defaultQueryParamValue, subQueryValue] : defaultQueryParamValue
162
+ const isNested = subQueryValue !== undefined
163
+ sharedFilter.queuedActive = isNested ? [queryValue, subQueryValue] : queryValue
168
164
  }
169
165
  return sharedFilter // no autoLoading happening
170
166
  }
171
- if (autoLoadFilterIndexes.includes(sharedFilterIndex) || hasQueryParameter) {
167
+ if (autoLoadFilterIndexes.includes(sharedFilterIndex) || hasQuery) {
172
168
  const filterParents = sharedFiltersCopy.filter(f => sharedFilter.parents?.includes(f.key))
173
- const notAllParentFiltersSelected = filterParents.some(p => !(p.active || p.queuedActive))
174
- if (filterParents && notAllParentFiltersSelected) return sharedFilter
169
+ const missingParents = filterParents.some(p => !(p.active || p.queuedActive))
170
+ if (missingParents) return sharedFilter
175
171
  if (sharedFilter.filterStyle === FILTER_STYLE.multiSelect) {
176
172
  setActiveMultiDropdown(dropdownOptions, sharedFilter)
177
173
  } else if (sharedFilter.filterStyle === FILTER_STYLE.nestedDropdown) {
@@ -179,7 +175,7 @@ export const setAutoLoadDefaultValue = (
179
175
  } else {
180
176
  const defaultValue = dropdownOptions[0]?.value
181
177
  if (!sharedFilter.active) {
182
- sharedFilter.active = defaultQueryParamValue || defaultValue
178
+ sharedFilter.active = queryValue ?? defaultValue
183
179
  } else {
184
180
  const currentOption = dropdownOptions.find(option => option.value == sharedFilter.active) // loose equality required: 2017 should equal '2017'
185
181
  sharedFilter.active = currentOption ? currentOption.value : defaultValue
@@ -1,65 +1,67 @@
1
- import _ from 'lodash'
2
- import { FilterBehavior } from '../helpers/FilterBehavior'
3
- import {
4
- getQueryParams,
5
- removeQueryParam,
6
- updateQueryParam,
7
- updateQueryString
8
- } from '@cdc/core/helpers/queryStringUtils'
9
- import { SharedFilter } from '../types/SharedFilter'
10
- import { DashboardFilters } from '../types/DashboardFilters'
11
- import { FILTER_STYLE } from '../types/FilterStyles'
12
-
13
- const handleChildren = (sharedFilters: SharedFilter[], parentIndex: number) => {
14
- const parentKey = sharedFilters[parentIndex].key
15
- const childFilterIndexes = sharedFilters
16
- .map((filter, index) => (filter.parents?.includes(parentKey) ? index : null))
17
- .filter(i => i !== null)
18
- if (childFilterIndexes.length) {
19
- childFilterIndexes.forEach(filterIndex => {
20
- const cur = sharedFilters[filterIndex]
21
- if (cur.setByQueryParameter) removeQueryParam(cur.setByQueryParameter)
22
- cur.active = ''
23
- if (cur.subGrouping) {
24
- cur.subGrouping.active = ''
25
- }
26
- })
27
- }
28
- return childFilterIndexes
29
- }
30
-
31
- export const changeFilterActive = (
32
- filterIndex: number,
33
- value: string | string[],
34
- sharedFilters: SharedFilter[],
35
- vizConfig: DashboardFilters
36
- ): [SharedFilter[], number[]] => {
37
- const sharedFiltersCopy = _.cloneDeep(sharedFilters)
38
- const currentFilter = sharedFiltersCopy[filterIndex]
39
- if (vizConfig.filterBehavior !== FilterBehavior.Apply || vizConfig.autoLoad) {
40
- if (currentFilter?.filterStyle === FILTER_STYLE.nestedDropdown) {
41
- sharedFiltersCopy[filterIndex].active = value[0]
42
- sharedFiltersCopy[filterIndex].subGrouping.active = value[1]
43
- } else {
44
- sharedFiltersCopy[filterIndex].active = value
45
- handleChildren(sharedFiltersCopy, filterIndex)
46
- const queryParams = getQueryParams()
47
- if (
48
- currentFilter.setByQueryParameter &&
49
- queryParams[currentFilter.setByQueryParameter] !== currentFilter.active
50
- ) {
51
- queryParams[currentFilter.setByQueryParameter] = currentFilter.active
52
- updateQueryString(queryParams)
53
- }
54
- }
55
- } else if (currentFilter.subGrouping) {
56
- updateQueryParam(currentFilter.setByQueryParameter, value[0])
57
- updateQueryParam(currentFilter.subGrouping.setByQueryParameter, value[1])
58
- sharedFiltersCopy[filterIndex].queuedActive = value
59
- } else {
60
- const paramVal = Array.isArray(value) ? value.join(',') : value
61
- if (currentFilter.setByQueryParameter) updateQueryParam(currentFilter.setByQueryParameter, paramVal)
62
- sharedFiltersCopy[filterIndex].queuedActive = value
63
- }
64
- return [sharedFiltersCopy, handleChildren(sharedFiltersCopy, filterIndex)]
65
- }
1
+ import _ from 'lodash'
2
+ import { FilterBehavior } from '../helpers/FilterBehavior'
3
+ import {
4
+ getQueryParams,
5
+ removeQueryParam,
6
+ updateQueryParam,
7
+ updateQueryString
8
+ } from '@cdc/core/helpers/queryStringUtils'
9
+ import { SharedFilter } from '../types/SharedFilter'
10
+ import { DashboardFilters } from '../types/DashboardFilters'
11
+ import { FILTER_STYLE } from '../types/FilterStyles'
12
+
13
+ const handleChildren = (sharedFilters: SharedFilter[], parentIndex: number) => {
14
+ const parentKey = sharedFilters[parentIndex].key
15
+ const childFilterIndexes = sharedFilters
16
+ .map((filter, index) => (filter.parents?.includes(parentKey) ? index : null))
17
+ .filter(i => i !== null)
18
+ if (childFilterIndexes.length) {
19
+ childFilterIndexes.forEach(filterIndex => {
20
+ const cur = sharedFilters[filterIndex]
21
+ if (cur.type === 'urlfilter') {
22
+ if (cur.setByQueryParameter) removeQueryParam(cur.setByQueryParameter)
23
+ cur.active = ''
24
+ if (cur.subGrouping) {
25
+ cur.subGrouping.active = ''
26
+ }
27
+ }
28
+ })
29
+ }
30
+ return childFilterIndexes
31
+ }
32
+
33
+ export const changeFilterActive = (
34
+ filterIndex: number,
35
+ value: string | string[],
36
+ sharedFilters: SharedFilter[],
37
+ vizConfig: DashboardFilters
38
+ ): [SharedFilter[], number[]] => {
39
+ const sharedFiltersCopy = _.cloneDeep(sharedFilters)
40
+ const currentFilter = sharedFiltersCopy[filterIndex]
41
+ if (vizConfig.filterBehavior !== FilterBehavior.Apply || vizConfig.autoLoad) {
42
+ if (currentFilter?.filterStyle === FILTER_STYLE.nestedDropdown) {
43
+ sharedFiltersCopy[filterIndex].active = value[0]
44
+ sharedFiltersCopy[filterIndex].subGrouping.active = value[1]
45
+ } else {
46
+ sharedFiltersCopy[filterIndex].active = value
47
+ handleChildren(sharedFiltersCopy, filterIndex)
48
+ const queryParams = getQueryParams()
49
+ if (
50
+ currentFilter.setByQueryParameter &&
51
+ queryParams[currentFilter.setByQueryParameter] !== currentFilter.active
52
+ ) {
53
+ queryParams[currentFilter.setByQueryParameter] = currentFilter.active
54
+ updateQueryString(queryParams)
55
+ }
56
+ }
57
+ } else if (currentFilter.subGrouping) {
58
+ updateQueryParam(currentFilter.setByQueryParameter, value[0])
59
+ updateQueryParam(currentFilter.subGrouping.setByQueryParameter, value[1])
60
+ sharedFiltersCopy[filterIndex].queuedActive = value
61
+ } else {
62
+ const paramVal = Array.isArray(value) ? value.join(',') : value
63
+ if (currentFilter.setByQueryParameter) updateQueryParam(currentFilter.setByQueryParameter, paramVal)
64
+ sharedFiltersCopy[filterIndex].queuedActive = value
65
+ }
66
+ return [sharedFiltersCopy, handleChildren(sharedFiltersCopy, filterIndex)]
67
+ }
@@ -17,11 +17,12 @@ const cleanDashboardFootnotes = (config: DashboardConfig) => {
17
17
  }
18
18
  }
19
19
 
20
- const cleanDashboardData = (config: DashboardConfig) => {
20
+ const cleanDashboardData = (config: DashboardConfig, isEditor = false) => {
21
21
  if (config.datasets) {
22
22
  Object.keys(config.datasets).forEach(datasetKey => {
23
23
  delete config.datasets[datasetKey].formattedData
24
- if (config.datasets[datasetKey].dataUrl) {
24
+ // Only delete data when not in editor mode
25
+ if (config.datasets[datasetKey].dataUrl && !isEditor) {
25
26
  delete config.datasets[datasetKey].data
26
27
  }
27
28
  })
@@ -104,12 +105,12 @@ const removeRuntimeDataURLs = (config: DashboardConfig) => {
104
105
  }
105
106
  }
106
107
 
107
- export const stripConfig = configToStrip => {
108
+ export const stripConfig = (configToStrip, isEditor = false) => {
108
109
  const strippedConfig = cloneConfig(configToStrip)
109
110
  if (strippedConfig.type === 'dashboard') {
110
111
  if (strippedConfig.multiDashboards) {
111
112
  strippedConfig.multiDashboards.forEach((multiDashboard, i) => {
112
- cleanDashboardData(strippedConfig.multiDashboards[i])
113
+ cleanDashboardData(strippedConfig.multiDashboards[i], isEditor)
113
114
  cleanSharedFilters(strippedConfig.multiDashboards[i])
114
115
  cleanDashboardFootnotes(strippedConfig.multiDashboards[i])
115
116
  cleanVisualizationFilters(strippedConfig.multiDashboards[i])
@@ -120,7 +121,7 @@ export const stripConfig = configToStrip => {
120
121
  delete strippedConfig.label
121
122
  }
122
123
  delete strippedConfig.activeDashboard
123
- cleanDashboardData(strippedConfig)
124
+ cleanDashboardData(strippedConfig, isEditor)
124
125
  cleanSharedFilters(strippedConfig)
125
126
  cleanDashboardFootnotes(strippedConfig)
126
127
  cleanVisualizationFilters(strippedConfig)
@@ -1,91 +1,91 @@
1
- import { DashboardState } from '../store/dashboard.reducer'
2
- import { DashboardConfig as Config, DashboardConfig } from '../types/DashboardConfig'
3
- import { filterData } from './filterData'
4
- import { generateValuesForFilter } from './generateValuesForFilter'
5
- import { getFormattedData } from './getFormattedData'
6
- import { getVizKeys } from './getVizKeys'
7
- import { getVizRowColumnLocator } from './getVizRowColumnLocator'
8
-
9
- import { getQueryStringFilterValue } from '@cdc/core/helpers/queryStringUtils'
10
-
11
- type UpdateState = Omit<DashboardState, 'config'> & {
12
- config?: DashboardConfig
13
- }
14
-
15
- export const getUpdateConfig =
16
- (state: UpdateState) =>
17
- (newConfig, dataOverride?: Object): [Config, Object] => {
18
- let newFilteredData = {}
19
- let visualizationKeys = getVizKeys(newConfig)
20
-
21
- const vizRowColumnLocator = getVizRowColumnLocator(newConfig.rows)
22
-
23
- if (newConfig.dashboard.sharedFilters) {
24
- newConfig.dashboard.sharedFilters.forEach((filter, i) => {
25
- const filterIsSetByVizData = !!visualizationKeys.find(key => key === filter.setBy)
26
- const _filter = newConfig.dashboard.sharedFilters[i]
27
-
28
- const setValuesAndActive = filterValues => {
29
- _filter.values = filterValues
30
- if (filterValues.length > 0) {
31
- const defaultValues = _filter.pivot ? _filter.values : _filter.values[0]
32
-
33
- const queryStringFilterValue = getQueryStringFilterValue(_filter)
34
- if (queryStringFilterValue) {
35
- _filter.active = queryStringFilterValue
36
- } else {
37
- _filter.active = _filter.active || defaultValues
38
- }
39
- }
40
- }
41
-
42
- const filterValues = generateValuesForFilter(filter.columnName, dataOverride || state.data)
43
- if (filterIsSetByVizData) {
44
- if (_filter.order === 'asc') {
45
- filterValues.sort()
46
- }
47
- if (_filter.order === 'desc') {
48
- filterValues.sort().reverse()
49
- }
50
-
51
- setValuesAndActive(filterValues)
52
- } else if ((!filter.values || filter.values.length === 0) && filter.showDropdown) {
53
- setValuesAndActive(filterValues)
54
- }
55
- })
56
-
57
- visualizationKeys.forEach(visualizationKey => {
58
- const row = vizRowColumnLocator[visualizationKey]
59
- if (newConfig.rows[row]?.datakey) return // data configured on the row level
60
- const applicableFilters = newConfig.dashboard.sharedFilters.filter(
61
- sharedFilter => sharedFilter.usedBy && sharedFilter.usedBy.indexOf(visualizationKey) !== -1
62
- )
63
-
64
- if (applicableFilters.length > 0) {
65
- const visualization = newConfig.visualizations[visualizationKey]
66
- const _newConfigDataSet = newConfig.datasets[visualization.dataKey]
67
- const formattedData = getFormattedData(
68
- _newConfigDataSet?.data || visualization.data,
69
- visualization.dataDescription
70
- )
71
- const _data = formattedData || (dataOverride || state.data)[visualization.dataKey]
72
- newFilteredData[visualizationKey] = filterData(applicableFilters, _data)
73
- }
74
- })
75
-
76
- newConfig.rows.forEach((row, rowIndex) => {
77
- const applicableFilters = newConfig.dashboard.sharedFilters.filter(
78
- sharedFilter => sharedFilter.usedBy && sharedFilter.usedBy.indexOf(rowIndex) !== -1
79
- )
80
-
81
- if (applicableFilters.length > 0) {
82
- const formattedData = getFormattedData(row.data, row.dataDescription)
83
- const _data = formattedData || (dataOverride || state.data)[rowIndex]
84
- newFilteredData[rowIndex] = filterData(applicableFilters, _data)
85
- }
86
- })
87
- }
88
- //Enforce default values that need to be calculated at runtime
89
- newConfig.runtime = {}
90
- return [newConfig, newFilteredData]
91
- }
1
+ import { DashboardState } from '../store/dashboard.reducer'
2
+ import { DashboardConfig as Config, DashboardConfig } from '../types/DashboardConfig'
3
+ import { filterData } from './filterData'
4
+ import { generateValuesForFilter } from './generateValuesForFilter'
5
+ import { getFormattedData } from './getFormattedData'
6
+ import { getVizKeys } from './getVizKeys'
7
+ import { getVizRowColumnLocator } from './getVizRowColumnLocator'
8
+
9
+ import { getQueryStringFilterValue } from '@cdc/core/helpers/queryStringUtils'
10
+
11
+ type UpdateState = Omit<DashboardState, 'config'> & {
12
+ config?: DashboardConfig
13
+ }
14
+
15
+ export const getUpdateConfig =
16
+ (state: UpdateState) =>
17
+ (newConfig, dataOverride?: Object): [Config, Object] => {
18
+ let newFilteredData = {}
19
+ let visualizationKeys = getVizKeys(newConfig)
20
+
21
+ const vizRowColumnLocator = getVizRowColumnLocator(newConfig.rows)
22
+
23
+ if (newConfig.dashboard.sharedFilters) {
24
+ newConfig.dashboard.sharedFilters.forEach((filter, i) => {
25
+ const filterIsSetByVizData = !!visualizationKeys.find(key => key === filter.setBy)
26
+ const _filter = newConfig.dashboard.sharedFilters[i]
27
+
28
+ const setValuesAndActive = filterValues => {
29
+ _filter.values = filterValues
30
+ if (filterValues.length > 0) {
31
+ const defaultValues = _filter.pivot ? _filter.values : _filter.values[0]
32
+
33
+ const queryStringFilterValue = getQueryStringFilterValue(_filter)
34
+ if (queryStringFilterValue) {
35
+ _filter.active = queryStringFilterValue
36
+ } else {
37
+ _filter.active = _filter.active || defaultValues
38
+ }
39
+ }
40
+ }
41
+
42
+ const filterValues = generateValuesForFilter(filter.columnName, dataOverride || state.data)
43
+ if (filterIsSetByVizData) {
44
+ if (_filter.order === 'asc') {
45
+ filterValues.sort()
46
+ }
47
+ if (_filter.order === 'desc') {
48
+ filterValues.sort().reverse()
49
+ }
50
+
51
+ setValuesAndActive(filterValues)
52
+ } else if ((!filter.values || filter.values.length === 0) && filter.showDropdown) {
53
+ setValuesAndActive(filterValues)
54
+ }
55
+ })
56
+
57
+ visualizationKeys.forEach(visualizationKey => {
58
+ const row = vizRowColumnLocator[visualizationKey]
59
+ if (newConfig.rows[row]?.datakey) return // data configured on the row level
60
+ const applicableFilters = newConfig.dashboard.sharedFilters.filter(
61
+ sharedFilter => sharedFilter.usedBy && sharedFilter.usedBy.indexOf(visualizationKey) !== -1
62
+ )
63
+
64
+ if (applicableFilters.length > 0) {
65
+ const visualization = newConfig.visualizations[visualizationKey]
66
+ const _newConfigDataSet = newConfig.datasets[visualization.dataKey]
67
+ const formattedData = getFormattedData(
68
+ _newConfigDataSet?.data || visualization.data,
69
+ visualization.dataDescription
70
+ )
71
+ const _data = formattedData || (dataOverride || state.data)[visualization.dataKey]
72
+ newFilteredData[visualizationKey] = filterData(applicableFilters, _data)
73
+ }
74
+ })
75
+
76
+ newConfig.rows.forEach((row, rowIndex) => {
77
+ const applicableFilters = newConfig.dashboard.sharedFilters.filter(
78
+ sharedFilter => sharedFilter.usedBy && sharedFilter.usedBy.indexOf(rowIndex) !== -1
79
+ )
80
+
81
+ if (applicableFilters.length > 0) {
82
+ const formattedData = getFormattedData(row.data, row.dataDescription)
83
+ const _data = formattedData || (dataOverride || state.data)[rowIndex]
84
+ newFilteredData[rowIndex] = filterData(applicableFilters, _data)
85
+ }
86
+ })
87
+ }
88
+ //Enforce default values that need to be calculated at runtime
89
+ newConfig.runtime = {}
90
+ return [newConfig, newFilteredData]
91
+ }