@cdc/dashboard 4.24.5 → 4.24.9-1

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 (86) hide show
  1. package/dist/cdcdashboard.js +147572 -128223
  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/examples/single-state-dashboard-filters.json +421 -0
  8. package/examples/state-level.json +90136 -0
  9. package/examples/state-points.json +10474 -0
  10. package/examples/test-file.json +147 -0
  11. package/examples/testing.json +94456 -0
  12. package/index.html +25 -4
  13. package/package.json +12 -11
  14. package/src/CdcDashboard.tsx +5 -1
  15. package/src/CdcDashboardComponent.tsx +250 -327
  16. package/src/DashboardContext.tsx +15 -1
  17. package/src/_stories/Dashboard.stories.tsx +158 -40
  18. package/src/_stories/_mock/api-filter-chart.json +11 -35
  19. package/src/_stories/_mock/api-filter-map.json +17 -31
  20. package/src/_stories/_mock/bump-chart.json +3554 -0
  21. package/src/_stories/_mock/methodology.json +412 -0
  22. package/src/_stories/_mock/methodologyAPI.ts +90 -0
  23. package/src/_stories/_mock/multi-viz.json +3 -4
  24. package/src/_stories/_mock/pivot-filter.json +14 -12
  25. package/src/_stories/_mock/single-state-dashboard-filters.json +390 -0
  26. package/src/components/CollapsibleVisualizationRow.tsx +44 -0
  27. package/src/components/Column.tsx +1 -1
  28. package/src/components/DashboardFilters/DashboardFilters.tsx +102 -0
  29. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +218 -0
  30. package/src/components/DashboardFilters/DashboardFiltersEditor/components/DeleteFilterModal.tsx +48 -0
  31. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +477 -0
  32. package/src/components/DashboardFilters/DashboardFiltersEditor/index.ts +1 -0
  33. package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +191 -0
  34. package/src/components/DashboardFilters/index.ts +3 -0
  35. package/src/components/DataDesignerModal.tsx +9 -9
  36. package/src/components/ExpandCollapseButtons.tsx +20 -0
  37. package/src/components/Header/Header.tsx +1 -102
  38. package/src/components/MultiConfigTabs/MultiConfigTabs.tsx +24 -12
  39. package/src/components/Row.tsx +52 -19
  40. package/src/components/Toggle/Toggle.tsx +2 -4
  41. package/src/components/VisualizationRow.tsx +169 -30
  42. package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +116 -0
  43. package/src/components/VisualizationsPanel/index.ts +1 -0
  44. package/src/components/VisualizationsPanel/visualizations-panel-styles.css +12 -0
  45. package/src/components/Widget.tsx +27 -90
  46. package/src/helpers/FilterBehavior.ts +4 -0
  47. package/src/helpers/addValuesToDashboardFilters.ts +49 -0
  48. package/src/helpers/apiFilterHelpers.ts +103 -0
  49. package/src/helpers/changeFilterActive.ts +39 -0
  50. package/src/helpers/filterData.ts +10 -48
  51. package/src/helpers/generateValuesForFilter.ts +1 -1
  52. package/src/helpers/getAutoLoadVisualization.ts +11 -0
  53. package/src/helpers/getFilteredData.ts +7 -5
  54. package/src/helpers/getVizConfig.ts +23 -2
  55. package/src/helpers/getVizRowColumnLocator.ts +2 -1
  56. package/src/helpers/hasDashboardApplyBehavior.ts +5 -0
  57. package/src/helpers/iconHash.tsx +5 -3
  58. package/src/helpers/loadAPIFilters.ts +74 -0
  59. package/src/helpers/mapDataToConfig.ts +29 -0
  60. package/src/helpers/processData.ts +2 -3
  61. package/src/helpers/reloadURLHelpers.ts +102 -0
  62. package/src/helpers/tests/addValuesToDashboardFilters.test.ts +44 -0
  63. package/src/helpers/tests/apiFilterHelpers.test.ts +155 -0
  64. package/src/helpers/tests/filterData.test.ts +1 -93
  65. package/src/helpers/tests/getFilteredData.test.ts +86 -0
  66. package/src/helpers/tests/loadAPIFiltersWrapper.test.ts +220 -0
  67. package/src/helpers/tests/reloadURLHelpers.test.ts +232 -0
  68. package/src/scss/editor-panel.scss +1 -1
  69. package/src/scss/grid.scss +34 -27
  70. package/src/scss/main.scss +41 -3
  71. package/src/scss/variables.scss +4 -0
  72. package/src/store/dashboard.actions.ts +12 -4
  73. package/src/store/dashboard.reducer.ts +30 -4
  74. package/src/types/APIFilter.ts +1 -5
  75. package/src/types/ConfigRow.ts +2 -0
  76. package/src/types/Dashboard.ts +1 -1
  77. package/src/types/DashboardConfig.ts +2 -4
  78. package/src/types/DashboardFilters.ts +7 -0
  79. package/src/types/InitialState.ts +1 -1
  80. package/src/types/MultiDashboard.ts +2 -2
  81. package/src/types/SharedFilter.ts +4 -6
  82. package/src/types/Tab.ts +1 -1
  83. package/src/components/Filters.tsx +0 -88
  84. package/src/components/Header/FilterModal.tsx +0 -510
  85. package/src/components/VisualizationsPanel.tsx +0 -95
  86. package/src/helpers/getApiFilterKey.ts +0 -5
@@ -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,23 +1,21 @@
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'
6
7
  queryParameter?: string
7
8
  setByQueryParameter?: string
8
9
  active?: string | string[]
9
- queuedActive?: string
10
+ queuedActive?: string | 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>
17
+ multiSelect?: boolean
19
18
  key: string
20
- values?: string[]
21
19
  apiFilter?: APIFilter
22
20
  datasetKey?: string
23
21
  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'
@@ -1,88 +0,0 @@
1
- import MultiSelect from '@cdc/core/components/MultiSelect'
2
- import { getApiFilterKey } from '../helpers/getApiFilterKey'
3
- import { SharedFilter } from '../types/SharedFilter'
4
-
5
- export type DropdownOptions = Record<'value' | 'text', string>[]
6
-
7
- export type APIFilterDropdowns = {
8
- // null means still loading
9
- [filtername: string]: null | DropdownOptions
10
- }
11
-
12
- type FilterProps = {
13
- hide?: number[]
14
- filters: SharedFilter[]
15
- apiFilterDropdowns: APIFilterDropdowns
16
- handleOnChange: Function
17
- }
18
-
19
- const Filters: React.FC<FilterProps> = ({ hide, filters, apiFilterDropdowns, handleOnChange }) => {
20
- const updateField = (_section, _subsection, fieldName, value) => {
21
- handleOnChange(fieldName, value)
22
- }
23
- return (
24
- <>
25
- {filters.map((singleFilter, filterIndex) => {
26
- if ((singleFilter.type !== 'urlfilter' && !singleFilter.showDropdown) || (hide && hide.indexOf(filterIndex) !== -1)) return <></>
27
- const values: JSX.Element[] = []
28
- const multiValues = []
29
- if (singleFilter.resetLabel) {
30
- values.push(
31
- <option key={`${singleFilter.resetLabel}-option`} value={singleFilter.resetLabel}>
32
- {singleFilter.resetLabel}
33
- </option>
34
- )
35
- }
36
- const _key = singleFilter.apiFilter ? getApiFilterKey(singleFilter.apiFilter) : undefined
37
- if (_key && apiFilterDropdowns[_key]) {
38
- // URL Filter
39
- apiFilterDropdowns[_key].forEach(({ text, value }, index) => {
40
- values.push(
41
- <option key={`${value}-option-${index}`} value={value}>
42
- {text}
43
- </option>
44
- )
45
- })
46
- } else {
47
- // Data Filter
48
- singleFilter.values?.forEach((filterOption, index) => {
49
- const labeledOpt = singleFilter.labels && singleFilter.labels[filterOption]
50
- values.push(
51
- <option key={`${singleFilter.key}-option-${index}`} value={filterOption}>
52
- {labeledOpt || filterOption}
53
- </option>
54
- )
55
- multiValues.push({ value: filterOption, label: labeledOpt || filterOption })
56
- })
57
- }
58
-
59
- return (
60
- <div className='cove-dashboard-filters' key={`${singleFilter.key}-filtersection-${filterIndex}`}>
61
- <section className='dashboard-filters-section'>
62
- {!singleFilter.pivot ? (
63
- <>
64
- <label htmlFor={`filter-${filterIndex}`}>{singleFilter.key}</label>
65
- <select
66
- id={`filter-${filterIndex}`}
67
- className='filter-select'
68
- data-index='0'
69
- value={singleFilter.queuedActive || singleFilter.active}
70
- onChange={val => {
71
- handleOnChange(filterIndex, val.target.value)
72
- }}
73
- >
74
- {values}
75
- </select>
76
- </>
77
- ) : (
78
- <MultiSelect label={singleFilter.key} options={multiValues} fieldName={filterIndex} updateField={updateField} selected={singleFilter.active as string[]} limit={singleFilter.selectLimit || 5} />
79
- )}
80
- </section>
81
- </div>
82
- )
83
- })}
84
- </>
85
- )
86
- }
87
-
88
- export default Filters