@cdc/dashboard 4.24.5 → 4.24.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/cdcdashboard.js +122872 -112065
  2. package/examples/custom/css/respiratory.css +236 -0
  3. package/examples/custom/js/respiratory.js +242 -0
  4. package/examples/default-multi-dataset-shared-filter.json +1729 -0
  5. package/examples/ed-visits-county-file.json +618 -0
  6. package/examples/filtered-dash.json +6 -21
  7. package/index.html +10 -1
  8. package/package.json +12 -11
  9. package/src/CdcDashboard.tsx +5 -1
  10. package/src/CdcDashboardComponent.tsx +165 -306
  11. package/src/DashboardContext.tsx +9 -1
  12. package/src/_stories/Dashboard.stories.tsx +38 -34
  13. package/src/_stories/_mock/api-filter-chart.json +11 -35
  14. package/src/_stories/_mock/api-filter-map.json +17 -31
  15. package/src/_stories/_mock/multi-viz.json +2 -3
  16. package/src/_stories/_mock/pivot-filter.json +14 -12
  17. package/src/components/CollapsibleVisualizationRow.tsx +44 -0
  18. package/src/components/Column.tsx +1 -1
  19. package/src/components/DashboardFilters/DashboardFilters.tsx +80 -0
  20. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +218 -0
  21. package/src/components/DashboardFilters/DashboardFiltersEditor/components/DeleteFilterModal.tsx +48 -0
  22. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +367 -0
  23. package/src/components/DashboardFilters/DashboardFiltersEditor/index.ts +1 -0
  24. package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +143 -0
  25. package/src/components/DashboardFilters/index.ts +3 -0
  26. package/src/components/DataDesignerModal.tsx +9 -9
  27. package/src/components/ExpandCollapseButtons.tsx +20 -0
  28. package/src/components/Header/Header.tsx +1 -97
  29. package/src/components/MultiConfigTabs/MultiConfigTabs.tsx +4 -4
  30. package/src/components/Row.tsx +52 -19
  31. package/src/components/Toggle/Toggle.tsx +2 -4
  32. package/src/components/VisualizationRow.tsx +82 -24
  33. package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +116 -0
  34. package/src/components/VisualizationsPanel/index.ts +1 -0
  35. package/src/components/VisualizationsPanel/visualizations-panel-styles.css +12 -0
  36. package/src/components/Widget.tsx +26 -90
  37. package/src/helpers/apiFilterHelpers.ts +51 -0
  38. package/src/helpers/changeFilterActive.ts +30 -0
  39. package/src/helpers/filterData.ts +10 -48
  40. package/src/helpers/generateValuesForFilter.ts +1 -1
  41. package/src/helpers/getAutoLoadVisualization.ts +11 -0
  42. package/src/helpers/getFilteredData.ts +4 -2
  43. package/src/helpers/getVizConfig.ts +23 -2
  44. package/src/helpers/getVizRowColumnLocator.ts +2 -1
  45. package/src/helpers/hasDashboardApplyBehavior.ts +5 -0
  46. package/src/helpers/iconHash.tsx +3 -3
  47. package/src/helpers/mapDataToConfig.ts +29 -0
  48. package/src/helpers/processData.ts +2 -3
  49. package/src/helpers/reloadURLHelpers.ts +68 -0
  50. package/src/helpers/tests/filterData.test.ts +1 -93
  51. package/src/scss/editor-panel.scss +1 -1
  52. package/src/scss/grid.scss +34 -27
  53. package/src/scss/main.scss +41 -3
  54. package/src/scss/variables.scss +4 -0
  55. package/src/store/dashboard.actions.ts +12 -4
  56. package/src/store/dashboard.reducer.ts +30 -4
  57. package/src/types/APIFilter.ts +1 -5
  58. package/src/types/ConfigRow.ts +2 -0
  59. package/src/types/Dashboard.ts +1 -1
  60. package/src/types/DashboardConfig.ts +2 -4
  61. package/src/types/DashboardFilters.ts +7 -0
  62. package/src/types/InitialState.ts +1 -1
  63. package/src/types/MultiDashboard.ts +2 -2
  64. package/src/types/SharedFilter.ts +2 -5
  65. package/src/types/Tab.ts +1 -1
  66. package/LICENSE +0 -201
  67. package/src/components/Filters.tsx +0 -88
  68. package/src/components/Header/FilterModal.tsx +0 -510
  69. package/src/components/VisualizationsPanel.tsx +0 -95
  70. package/src/helpers/getApiFilterKey.ts +0 -5
@@ -1,10 +1,9 @@
1
- import { FilterBehavior } from '../components/Header/Header'
2
1
  import { DataSet } from '../types/DataSet'
3
2
  import fetchRemoteData from '@cdc/core/helpers/fetchRemoteData'
4
3
  import { getFormattedData } from './getFormattedData'
5
4
 
6
- export const processData = async (dataSet: DataSet, filterBehavior) => {
7
- if (dataSet.dataUrl && filterBehavior !== FilterBehavior.Apply) {
5
+ export const processData = async (dataSet: DataSet, hasFilterChangeBehavior: boolean) => {
6
+ if (dataSet.dataUrl && hasFilterChangeBehavior) {
8
7
  const dataset = await fetchRemoteData(`${dataSet.dataUrl}`)
9
8
  return getFormattedData(dataset, dataSet.dataDescription)
10
9
  }
@@ -0,0 +1,68 @@
1
+ import { gatherQueryParams } from '@cdc/core/helpers/gatherQueryParams'
2
+ import { SharedFilter } from '../types/SharedFilter'
3
+ import { capitalizeSplitAndJoin } from '@cdc/core/helpers/cove/string'
4
+ import { Visualization } from '@cdc/core/types/Visualization'
5
+ import _ from 'lodash'
6
+
7
+ export const isUpdateNeeded = (filters: SharedFilter[], currentQueryParams: Record<string, string>, newQueryParams: Record<string, string>): boolean => {
8
+ let needsUpdate = false
9
+ filters.find(filter => {
10
+ if (filter.type === 'urlfilter' && !Array.isArray(filter.active) && filter.filterBy === 'File Name') {
11
+ needsUpdate = true
12
+ return true
13
+ }
14
+ })
15
+ Object.keys(newQueryParams).forEach(updatedParam => {
16
+ if (decodeURIComponent(newQueryParams[updatedParam]) !== currentQueryParams[updatedParam]) {
17
+ needsUpdate = true
18
+ }
19
+ })
20
+ return needsUpdate
21
+ }
22
+
23
+ export const getDataURL = (updatedQSParams: Record<string, string>, dataUrl: URL, newFileName: string) => {
24
+ const _params = Object.keys(updatedQSParams).map(key => ({ key, value: updatedQSParams[key] }))
25
+ const baseURL = dataUrl.origin + dataUrl.pathname
26
+ let dataUrlFinal = `${baseURL}${gatherQueryParams(baseURL, _params)}`
27
+
28
+ if (newFileName !== '') {
29
+ const fileExtension = dataUrl.pathname.split('.').pop()
30
+ const pathWithoutFilename = dataUrl.pathname.substring(0, dataUrl.pathname.lastIndexOf('/'))
31
+ dataUrlFinal = `${dataUrl.origin}${pathWithoutFilename}/${newFileName}.${fileExtension}${gatherQueryParams(baseURL, _params)}`
32
+ }
33
+ return dataUrlFinal
34
+ }
35
+
36
+ export const getNewFileName = (newFileName: string, filter: SharedFilter, datasetKey: string) => {
37
+ const replacements = {
38
+ 'Remove Spaces': '',
39
+ 'Keep Spaces': ' ',
40
+ 'Replace With Underscore': '_'
41
+ }
42
+ let fileName = newFileName
43
+ if (filter.datasetKey === datasetKey) {
44
+ if (filter.fileName) {
45
+ // if a file name is found, ie, state_${query}, use that, ie. state_activeFilter.json
46
+ fileName = capitalizeSplitAndJoin.call(String(filter.fileName), ' ', replacements[filter.whitespaceReplacement ?? 'Keep Spaces'])
47
+ } else {
48
+ // if no file name is entered use the default active filter. ie. /activeFilter.json
49
+ fileName = filter.active as string
50
+ }
51
+ }
52
+
53
+ if (fileName?.includes('${query}')) {
54
+ fileName = fileName.replace('${query}', capitalizeSplitAndJoin.call(String(filter.active), ' ', replacements[filter.whitespaceReplacement ?? 'Keep Spaces']))
55
+ }
56
+
57
+ return fileName
58
+ }
59
+
60
+ export const getVisualizationsWithFormattedData = (visualizations: Record<string, Visualization>, newData: Object) => {
61
+ return Object.keys(visualizations).reduce((acc, vizKey) => {
62
+ const dataKey = visualizations[vizKey].dataKey
63
+ if (newData[dataKey]) {
64
+ acc[vizKey].formattedData = newData[dataKey]
65
+ }
66
+ return acc
67
+ }, _.cloneDeep(visualizations))
68
+ }
@@ -1,3 +1,4 @@
1
+ import _ from 'lodash'
1
2
  import { SharedFilter } from '../../types/SharedFilter'
2
3
  import { filterData } from '../filterData'
3
4
 
@@ -36,48 +37,6 @@ describe('filterData', () => {
36
37
  expect(result).toEqual([{ name: 'John', age: 30 }])
37
38
  })
38
39
 
39
- it('causes sideEffects to filters', () => {
40
- // the side effect is not desired, but current functionality depends on the sideEffect.
41
- // hopefully the side effect will be refactored in the future to be a returned value.
42
- const filters = [
43
- { columnName: 'name', active: 'John', queuedActive: 'John', fileName: 'abc', key: 'name' },
44
- { columnName: 'age', fileName: 'abc', key: 'age' },
45
- { columnName: 'color', fileName: 'abc', key: 'color', parents: ['age'] }
46
- ] as SharedFilter[]
47
- const data = [
48
- { name: 'John', age: 30, color: 'blue' },
49
- { name: 'Jane', age: 25, color: 'red' },
50
- { name: 'John', age: 35, color: 'yellow' },
51
- { name: 'Jane', age: 30, color: 'green' }
52
- ]
53
-
54
- const result = filterData(filters, data)
55
-
56
- expect(result).toEqual([{ name: 'John', age: 30, color: 'blue' }])
57
-
58
- const sideEffectOfFiltering = [
59
- {
60
- columnName: 'name',
61
- active: 'John',
62
- queuedActive: 'John',
63
- fileName: 'abc',
64
- key: 'name',
65
- tier: 1
66
- },
67
- { columnName: 'age', fileName: 'abc', key: 'age', tier: 1 },
68
- {
69
- columnName: 'color',
70
- fileName: 'abc',
71
- key: 'color',
72
- parents: ['age'],
73
- tier: 2,
74
- values: ['blue', 'yellow'],
75
- active: 'blue'
76
- }
77
- ]
78
- expect(filters).toEqual(sideEffectOfFiltering)
79
- })
80
-
81
40
  it('should not include data that does not meet the filter criteria', () => {
82
41
  const filters = [
83
42
  //{ columnName: 'apple', fileName: 'abc', key: 'banana' },
@@ -95,55 +54,4 @@ describe('filterData', () => {
95
54
  const result = filterData(filters, data)
96
55
  expect(result).toEqual([{ name: 'John', age: 25, color: 'red' }])
97
56
  })
98
-
99
- it('should pivot data based on the provided filters', () => {
100
- const filters = [{ key: 'Race', type: 'datafilter', showDropdown: true, columnName: 'Race', pivot: 'Age-adjusted rate', usedBy: ['table1707935263149'] }] as SharedFilter[]
101
- const data = [
102
- {
103
- Race: 'Hispanic or Latino',
104
- 'Age-adjusted rate': '644.2',
105
- Year: '2016'
106
- },
107
- {
108
- Race: 'Non-Hispanic American Indian',
109
- 'Age-adjusted rate': '636.1',
110
- Year: '2016'
111
- },
112
- {
113
- Race: 'Non-Hispanic Black',
114
- 'Age-adjusted rate': '563.7',
115
- Year: '2016'
116
- },
117
- {
118
- Race: 'Hispanic or Latino',
119
- 'Age-adjusted rate': '644.2',
120
- Year: '2017'
121
- },
122
- {
123
- Race: 'Non-Hispanic American Indian',
124
- 'Age-adjusted rate': '636.1',
125
- Year: '2017'
126
- },
127
- {
128
- Race: 'Non-Hispanic Black',
129
- 'Age-adjusted rate': '563.7',
130
- Year: '2017'
131
- }
132
- ]
133
-
134
- expect(filterData(filters, data)).toEqual([
135
- {
136
- 'Hispanic or Latino': '644.2',
137
- 'Non-Hispanic American Indian': '636.1',
138
- 'Non-Hispanic Black': '563.7',
139
- Year: '2016'
140
- },
141
- {
142
- 'Hispanic or Latino': '644.2',
143
- 'Non-Hispanic American Indian': '636.1',
144
- 'Non-Hispanic Black': '563.7',
145
- Year: '2017'
146
- }
147
- ])
148
- })
149
57
  })
@@ -249,7 +249,7 @@
249
249
  }
250
250
  &.checkbox {
251
251
  display: flex;
252
- span {
252
+ span:not(.cove-icon) {
253
253
  display: inline;
254
254
  }
255
255
  input {
@@ -7,15 +7,6 @@ $red: #f74242;
7
7
  margin-left: calc($editorWidth + 1em);
8
8
  }
9
9
 
10
- .visualizations-panel {
11
- background-color: #fff;
12
- padding: 1em;
13
- width: $editorWidth;
14
- border-right: #c7c7c7 1px solid;
15
- z-index: 1;
16
- overflow-y: scroll;
17
- }
18
-
19
10
  .hidden.editor-panel + .builder-grid {
20
11
  margin-left: 0 !important;
21
12
  }
@@ -30,30 +21,16 @@ $red: #f74242;
30
21
  padding: 5em 3em 3em;
31
22
  }
32
23
 
33
- .column-container {
34
- display: flex;
35
- flex-flow: row;
36
- width: 100%;
37
- position: relative;
38
- padding: 2em 1em 1em;
39
- border: 1px solid #c2c2c2;
40
- transition: border 300ms cubic-bezier(0.16, 1, 0.3, 1);
41
- background-color: #f2f2f2;
42
- user-select: none;
43
-
44
- &.can-drop {
45
- border-color: $blue-light;
46
- }
47
- }
48
-
49
24
  .row-menu {
50
25
  display: flex;
51
26
  align-items: flex-start;
52
27
  transition: opacity 300ms cubic-bezier(0.16, 1, 0.3, 1);
53
28
  user-select: none;
54
- position: relative;
29
+ position: absolute;
55
30
  z-index: 1;
56
- bottom: -1px;
31
+ top: -27px;
32
+ width: 100%;
33
+ left: 0;
57
34
 
58
35
  > li:not(.spacer) + li:not(.spacer) {
59
36
  margin-left: 0.3em;
@@ -337,6 +314,35 @@ $red: #f74242;
337
314
  top: 0;
338
315
  }
339
316
 
317
+ .footnotes {
318
+ margin: 0.5rem;
319
+ margin-bottom: 0;
320
+ width: calc(100% - 1rem);
321
+ border: 1px solid #c2c2c2;
322
+ transition: background-color 300ms cubic-bezier(0.16, 1, 0.3, 1);
323
+ background-color: #c2c2c2;
324
+ &:hover {
325
+ border-color: $blue;
326
+ background-color: $blue;
327
+ }
328
+ }
329
+
330
+ padding: 2em 1em 1em;
331
+ border: 1px solid #c2c2c2;
332
+ transition: border 300ms cubic-bezier(0.16, 1, 0.3, 1);
333
+ background-color: #f2f2f2;
334
+ user-select: none;
335
+
336
+ &.can-drop {
337
+ border-color: $blue-light;
338
+ }
339
+
340
+ .column-container {
341
+ display: flex;
342
+ flex-flow: row;
343
+ width: 100%;
344
+ }
345
+
340
346
  .widget__content {
341
347
  padding: 0 2em;
342
348
 
@@ -369,5 +375,6 @@ $red: #f74242;
369
375
  .column-container {
370
376
  border-color: $blue;
371
377
  }
378
+ border-color: $blue;
372
379
  }
373
380
  }
@@ -156,6 +156,13 @@
156
156
  z-index: -1;
157
157
  position: relative;
158
158
  }
159
+
160
+ // Expand and Collapse Buttons for Multiviz Dashboard
161
+ &.expand-collapse-buttons {
162
+ background-color: var(--lightestGray);
163
+ border: 1px var(--lightGray) solid;
164
+ color: black;
165
+ }
159
166
  }
160
167
 
161
168
  .warning-icon {
@@ -181,6 +188,40 @@
181
188
  }
182
189
  }
183
190
 
191
+ .collapsable-multiviz-container {
192
+ position: relative;
193
+ border: $lightGray 1px solid;
194
+ clear: both;
195
+ margin-bottom: 20px;
196
+ .multi-visualiation-heading {
197
+ position: relative;
198
+ background: var(--lightestGray);
199
+ padding: 0.5em 0.7em;
200
+ cursor: pointer;
201
+ svg {
202
+ position: absolute;
203
+ height: 100%;
204
+ width: 15px;
205
+ top: 0;
206
+ right: 1em;
207
+ }
208
+
209
+ &:focus {
210
+ z-index: 2;
211
+ position: relative;
212
+ }
213
+ @include breakpoint(xs) {
214
+ font-size: $font-small + 0.2em;
215
+ }
216
+ }
217
+ .data-table-heading {
218
+ display: none;
219
+ }
220
+ .table-container {
221
+ margin: 0 1em;
222
+ }
223
+ }
224
+
184
225
  .dashboard-download-link {
185
226
  font-size: 14px;
186
227
  }
@@ -205,9 +246,6 @@
205
246
  margin-left: 0;
206
247
  margin-right: 0;
207
248
  }
208
- &.hidden-toggle {
209
- display: none;
210
- }
211
249
  }
212
250
 
213
251
  .dashboard-col-12 {
@@ -1 +1,5 @@
1
1
  $editorWidth: 350px;
2
+
3
+ :root {
4
+ --editorWidth: #{$editorWidth};
5
+ }
@@ -1,15 +1,20 @@
1
1
  import type { DashboardConfig as Config } from '../types/DashboardConfig'
2
2
  import { type Action } from '@cdc/core/types/Action'
3
3
  import { Tab } from '../types/Tab'
4
- import { ConfigureData } from '@cdc/core/types/ConfigureData'
5
4
  import { ConfigRow } from '../types/ConfigRow'
5
+ import { AnyVisualization } from '@cdc/core/types/Visualization'
6
+ import Footnotes from '@cdc/core/types/Footnotes'
7
+ import { SharedFilter } from '../types/SharedFilter'
6
8
 
7
- type SET_CONFIG = Action<'SET_CONFIG', Config>
9
+ type ADD_FOOTNOTE = Action<'ADD_FOOTNOTE', { id: string; rowIndex: number; config: Footnotes }>
10
+ type APPLY_CONFIG = Action<'APPLY_CONFIG', [Config, Object?]>
11
+ type SET_CONFIG = Action<'SET_CONFIG', Partial<Config>>
8
12
  type UPDATE_CONFIG = Action<'UPDATE_CONFIG', [Config, Object?]>
9
- type SET_DATA = Action<'SET_DATA', Object>
13
+ type SET_DATA = Action<'SET_DATA', Record<string, any[]>>
10
14
  type SET_LOADING = Action<'SET_LOADING', boolean>
11
15
  type SET_PREVIEW = Action<'SET_PREVIEW', boolean>
12
16
  type SET_FILTERED_DATA = Action<'SET_FILTERED_DATA', Object>
17
+ type SET_SHARED_FILTERS = Action<'SET_SHARED_FILTERS', SharedFilter[]>
13
18
  type SET_TAB_SELECTED = Action<'SET_TAB_SELECTED', Tab>
14
19
  type RENAME_DASHBOARD_TAB = Action<'RENAME_DASHBOARD_TAB', { current: string; new: string }>
15
20
  type INITIALIZE_MULTIDASHBOARDS = Action<'INITIALIZE_MULTIDASHBOARDS', undefined>
@@ -19,10 +24,12 @@ type ADD_NEW_DASHBOARD = Action<'ADD_NEW_DASHBOARD', undefined>
19
24
  type SAVE_CURRENT_CHANGES = Action<'SAVE_CURRENT_CHANGES', undefined>
20
25
  type SWITCH_CONFIG = Action<'SWITCH_CONFIG', number>
21
26
  type TOGGLE_ROW = Action<'TOGGLE_ROW', { rowIndex: number; colIndex: number }>
22
- type UPDATE_VISUALIZATION = Action<'UPDATE_VISUALIZATION', { vizKey: string; configureData: Partial<ConfigureData> }>
27
+ type UPDATE_VISUALIZATION = Action<'UPDATE_VISUALIZATION', { vizKey: string; configureData: Partial<AnyVisualization> }>
23
28
  type UPDATE_ROW = Action<'UPDATE_ROW', { rowIndex: number; rowData: Partial<ConfigRow> }>
24
29
 
25
30
  type DashboardActions =
31
+ | ADD_FOOTNOTE
32
+ | APPLY_CONFIG
26
33
  | ADD_NEW_DASHBOARD
27
34
  | SET_CONFIG
28
35
  | UPDATE_CONFIG
@@ -34,6 +41,7 @@ type DashboardActions =
34
41
  | SET_LOADING
35
42
  | SET_PREVIEW
36
43
  | SET_FILTERED_DATA
44
+ | SET_SHARED_FILTERS
37
45
  | SET_TAB_SELECTED
38
46
  | SWITCH_CONFIG
39
47
  | INITIALIZE_MULTIDASHBOARDS
@@ -1,11 +1,13 @@
1
1
  import _ from 'lodash'
2
2
  import { getUpdateConfig } from '../helpers/getUpdateConfig'
3
- import { MultiDashboard, MultiDashboardConfig } from '../types/MultiDashboard'
3
+ import { MultiDashboardConfig } from '../types/MultiDashboard'
4
4
  import DashboardActions from './dashboard.actions'
5
5
  import { devToolsWrapper } from '@cdc/core/helpers/withDevTools'
6
6
  import { Tab } from '../types/Tab'
7
7
  import { DashboardConfig } from '../types/DashboardConfig'
8
8
  import { ConfigRow } from '../types/ConfigRow'
9
+ import { AnyVisualization } from '@cdc/core/types/Visualization'
10
+ import { initialState } from '../DashboardContext'
9
11
 
10
12
  type BlankMultiConfig = {
11
13
  dashboard: Partial<DashboardConfig>
@@ -28,7 +30,7 @@ const createBlankDashboard: () => BlankMultiConfig = () => ({
28
30
 
29
31
  export type DashboardState = {
30
32
  config: MultiDashboardConfig
31
- data: Object
33
+ data: Record<string, any[]>
32
34
  filteredData: Object
33
35
  loading: boolean
34
36
  preview: boolean
@@ -37,6 +39,11 @@ export type DashboardState = {
37
39
 
38
40
  const reducer = (state: DashboardState, action: DashboardActions): DashboardState => {
39
41
  switch (action.type) {
42
+ case 'ADD_FOOTNOTE': {
43
+ const { id, rowIndex, config } = action.payload
44
+ const newRows = state.config.rows.map((row, i) => (i === rowIndex ? { ...row, footnotesId: id } : row))
45
+ return { ...state, config: { ...state.config, rows: newRows, visualizations: { ...state.config.visualizations, [id]: config } } }
46
+ }
40
47
  case 'ADD_NEW_DASHBOARD': {
41
48
  const currentMultiDashboards = state.config.multiDashboards
42
49
  const label = 'New Dashboard ' + (currentMultiDashboards.length + 1)
@@ -47,8 +54,21 @@ const reducer = (state: DashboardState, action: DashboardActions): DashboardStat
47
54
  const [config, filteredData] = getUpdateConfig(state)(...action.payload)
48
55
  return { ...state, config, filteredData }
49
56
  }
57
+ case 'APPLY_CONFIG': {
58
+ // using advanced editor. Wipe all existing data and apply new config
59
+ const [config, filteredData] = getUpdateConfig(state)(...action.payload)
60
+ // get the default data state
61
+ const data = [...Object.values(config.visualizations), ...config.rows]
62
+ .map(viz => viz.dataKey)
63
+ .reduce((acc, key) => {
64
+ const data = state.data[key] || state.config.datasets[key]?.data
65
+ if (data) acc[key] = data
66
+ return acc
67
+ }, {})
68
+ return { ...initialState, config, filteredData, data }
69
+ }
50
70
  case 'SET_CONFIG': {
51
- return { ...state, config: action.payload }
71
+ return { ...state, config: { ...state.config, ...action.payload } }
52
72
  }
53
73
  case 'SET_DATA': {
54
74
  return { ...state, data: action.payload }
@@ -62,6 +82,11 @@ const reducer = (state: DashboardState, action: DashboardActions): DashboardStat
62
82
  case 'SET_PREVIEW': {
63
83
  return { ...state, preview: action.payload }
64
84
  }
85
+ case 'SET_SHARED_FILTERS': {
86
+ const newSharedFilters = action.payload
87
+ const newDashboardConfig = { ...state.config.dashboard, sharedFilters: newSharedFilters }
88
+ return { ...state, config: { ...state.config, dashboard: newDashboardConfig } }
89
+ }
65
90
  case 'SET_TAB_SELECTED': {
66
91
  return { ...state, tabSelected: action.payload }
67
92
  }
@@ -124,7 +149,8 @@ const reducer = (state: DashboardState, action: DashboardActions): DashboardStat
124
149
  }
125
150
  case 'UPDATE_VISUALIZATION': {
126
151
  const { vizKey, configureData } = action.payload
127
- return { ...state, config: { ...state.config, visualizations: { ...state.config.visualizations, [vizKey]: { ...state.config.visualizations[vizKey], ...configureData } } } }
152
+ const updatedViz = { ...state.config.visualizations[vizKey], ...configureData } as AnyVisualization
153
+ return { ...state, config: { ...state.config, visualizations: { ...state.config.visualizations, [vizKey]: updatedViz } } }
128
154
  }
129
155
  case 'UPDATE_ROW': {
130
156
  const { rowIndex, rowData } = action.payload
@@ -1,5 +1 @@
1
- export type APIFilter = Record<'apiEndpoint'|'valueSelector'|'textSelector', string> & {
2
- heirarchyLookup?: string
3
- autoLoad?: boolean
4
- defaultValue?: string
5
- }
1
+ export type APIFilter = Record<'apiEndpoint' | 'valueSelector' | 'textSelector', string>
@@ -10,8 +10,10 @@ type Col = {
10
10
 
11
11
  export type ConfigRow = {
12
12
  columns: Col[]
13
+ expandCollapseAllButtons: boolean
13
14
  uuid?: string | number
14
15
  toggle?: boolean
15
16
  equalHeight?: boolean
16
17
  multiVizColumn?: string
18
+ footnotesId?: string // id for the footnotes in the vizConfig section
17
19
  } & ConfigureData
@@ -7,5 +7,5 @@ export type Dashboard = {
7
7
  description: any
8
8
  title: any
9
9
  theme: any
10
- filters: any
10
+ filters: any // deprecate
11
11
  }
@@ -2,21 +2,19 @@ import { Series } from '@cdc/core/types/Series'
2
2
  import { Runtime } from '@cdc/core/types/Runtime'
3
3
  import { DataSet } from './DataSet'
4
4
  import { ConfigRow } from './ConfigRow'
5
- import { Visualization } from '@cdc/core/types/Visualization'
5
+ import { AnyVisualization } from '@cdc/core/types/Visualization'
6
6
  import { Table } from '@cdc/core/types/Table'
7
- import { FilterBehavior } from '@cdc/core/types/FilterBehavior'
8
7
  import { Dashboard } from './Dashboard'
9
8
 
10
9
  export type DashboardConfig = DataSet & {
11
10
  dashboard: Dashboard
12
11
  confidenceKeys: Record<string, any>
13
- visualizations: Record<string, Visualization>
12
+ visualizations: Record<string, AnyVisualization>
14
13
  series: Series
15
14
  datasets: Record<string, DataSet>
16
15
  dataFileName: string
17
16
  table: Table
18
17
  rows: ConfigRow[]
19
- filterBehavior: FilterBehavior
20
18
  runtime: Runtime
21
19
  downloadImageButton: boolean
22
20
  downloadPdfButton: boolean
@@ -0,0 +1,7 @@
1
+ import { CommonVisualizationProperties } from '@cdc/core/types/Visualization'
2
+
3
+ export type DashboardFilters = {
4
+ sharedFilterIndexes: number[]
5
+ autoLoad?: boolean
6
+ type: 'dashboardFilters'
7
+ } & CommonVisualizationProperties
@@ -3,7 +3,7 @@ import { Tab } from './Tab'
3
3
 
4
4
  export type InitialState = {
5
5
  config: DashboardConfig
6
- data: Object
6
+ data: Record<string, any[]>
7
7
  loading: boolean
8
8
  filteredData: Object
9
9
  preview: boolean
@@ -1,9 +1,9 @@
1
- import { Visualization } from '@cdc/core/types/Visualization'
1
+ import { AnyVisualization } from '@cdc/core/types/Visualization'
2
2
  import { Dashboard } from './Dashboard'
3
3
  import { DashboardConfig } from './DashboardConfig'
4
4
  import { ConfigRow } from './ConfigRow'
5
5
 
6
- export type MultiDashboard = { dashboard: Dashboard; rows: ConfigRow[]; visualizations: Record<string, Visualization>; label: string }
6
+ export type MultiDashboard = { dashboard: Dashboard; rows: ConfigRow[]; visualizations: Record<string, AnyVisualization>; label: string }
7
7
 
8
8
  export type MultiDashboardConfig = DashboardConfig & {
9
9
  multiDashboards?: MultiDashboard[]
@@ -1,5 +1,6 @@
1
+ import { FilterBase } from '@cdc/core/types/VizFilter'
1
2
  import { APIFilter } from './APIFilter'
2
- export type SharedFilter = {
3
+ export type SharedFilter = FilterBase & {
3
4
  type?: 'urlfilter' | 'datafilter' | ''
4
5
  fileName?: string
5
6
  filterBy?: 'Query String' | 'File Name'
@@ -9,15 +10,11 @@ export type SharedFilter = {
9
10
  queuedActive?: string
10
11
  usedBy?: (string | number)[] // if number used by whole row, else used by specific viz
11
12
  parents?: string[]
12
- pivot?: string
13
13
  setBy?: string
14
14
  selectLimit?: number
15
- columnName?: string
16
15
  resetLabel?: string
17
- showDropdown?: boolean
18
16
  labels?: Record<string, any>
19
17
  key: string
20
- values?: string[]
21
18
  apiFilter?: APIFilter
22
19
  datasetKey?: string
23
20
  tier?: number
package/src/types/Tab.ts CHANGED
@@ -1 +1 @@
1
- export type Tab = 'Dashboard Description' | 'Dashboard Filters' | 'Data Table Settings' | 'Dashboard Preview'
1
+ export type Tab = 'Dashboard Description' | 'Data Table Settings' | 'Dashboard Preview'