@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.
- package/dist/cdcdashboard.js +147572 -128223
- package/examples/custom/css/respiratory.css +236 -0
- package/examples/custom/js/respiratory.js +242 -0
- package/examples/default-multi-dataset-shared-filter.json +1729 -0
- package/examples/ed-visits-county-file.json +618 -0
- package/examples/filtered-dash.json +6 -21
- package/examples/single-state-dashboard-filters.json +421 -0
- package/examples/state-level.json +90136 -0
- package/examples/state-points.json +10474 -0
- package/examples/test-file.json +147 -0
- package/examples/testing.json +94456 -0
- package/index.html +25 -4
- package/package.json +12 -11
- package/src/CdcDashboard.tsx +5 -1
- package/src/CdcDashboardComponent.tsx +250 -327
- package/src/DashboardContext.tsx +15 -1
- package/src/_stories/Dashboard.stories.tsx +158 -40
- package/src/_stories/_mock/api-filter-chart.json +11 -35
- package/src/_stories/_mock/api-filter-map.json +17 -31
- package/src/_stories/_mock/bump-chart.json +3554 -0
- package/src/_stories/_mock/methodology.json +412 -0
- package/src/_stories/_mock/methodologyAPI.ts +90 -0
- package/src/_stories/_mock/multi-viz.json +3 -4
- package/src/_stories/_mock/pivot-filter.json +14 -12
- package/src/_stories/_mock/single-state-dashboard-filters.json +390 -0
- package/src/components/CollapsibleVisualizationRow.tsx +44 -0
- package/src/components/Column.tsx +1 -1
- package/src/components/DashboardFilters/DashboardFilters.tsx +102 -0
- package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +218 -0
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/DeleteFilterModal.tsx +48 -0
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +477 -0
- package/src/components/DashboardFilters/DashboardFiltersEditor/index.ts +1 -0
- package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +191 -0
- package/src/components/DashboardFilters/index.ts +3 -0
- package/src/components/DataDesignerModal.tsx +9 -9
- package/src/components/ExpandCollapseButtons.tsx +20 -0
- package/src/components/Header/Header.tsx +1 -102
- package/src/components/MultiConfigTabs/MultiConfigTabs.tsx +24 -12
- package/src/components/Row.tsx +52 -19
- package/src/components/Toggle/Toggle.tsx +2 -4
- package/src/components/VisualizationRow.tsx +169 -30
- package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +116 -0
- package/src/components/VisualizationsPanel/index.ts +1 -0
- package/src/components/VisualizationsPanel/visualizations-panel-styles.css +12 -0
- package/src/components/Widget.tsx +27 -90
- package/src/helpers/FilterBehavior.ts +4 -0
- package/src/helpers/addValuesToDashboardFilters.ts +49 -0
- package/src/helpers/apiFilterHelpers.ts +103 -0
- package/src/helpers/changeFilterActive.ts +39 -0
- package/src/helpers/filterData.ts +10 -48
- package/src/helpers/generateValuesForFilter.ts +1 -1
- package/src/helpers/getAutoLoadVisualization.ts +11 -0
- package/src/helpers/getFilteredData.ts +7 -5
- package/src/helpers/getVizConfig.ts +23 -2
- package/src/helpers/getVizRowColumnLocator.ts +2 -1
- package/src/helpers/hasDashboardApplyBehavior.ts +5 -0
- package/src/helpers/iconHash.tsx +5 -3
- package/src/helpers/loadAPIFilters.ts +74 -0
- package/src/helpers/mapDataToConfig.ts +29 -0
- package/src/helpers/processData.ts +2 -3
- package/src/helpers/reloadURLHelpers.ts +102 -0
- package/src/helpers/tests/addValuesToDashboardFilters.test.ts +44 -0
- package/src/helpers/tests/apiFilterHelpers.test.ts +155 -0
- package/src/helpers/tests/filterData.test.ts +1 -93
- package/src/helpers/tests/getFilteredData.test.ts +86 -0
- package/src/helpers/tests/loadAPIFiltersWrapper.test.ts +220 -0
- package/src/helpers/tests/reloadURLHelpers.test.ts +232 -0
- package/src/scss/editor-panel.scss +1 -1
- package/src/scss/grid.scss +34 -27
- package/src/scss/main.scss +41 -3
- package/src/scss/variables.scss +4 -0
- package/src/store/dashboard.actions.ts +12 -4
- package/src/store/dashboard.reducer.ts +30 -4
- package/src/types/APIFilter.ts +1 -5
- package/src/types/ConfigRow.ts +2 -0
- package/src/types/Dashboard.ts +1 -1
- package/src/types/DashboardConfig.ts +2 -4
- package/src/types/DashboardFilters.ts +7 -0
- package/src/types/InitialState.ts +1 -1
- package/src/types/MultiDashboard.ts +2 -2
- package/src/types/SharedFilter.ts +4 -6
- package/src/types/Tab.ts +1 -1
- package/src/components/Filters.tsx +0 -88
- package/src/components/Header/FilterModal.tsx +0 -510
- package/src/components/VisualizationsPanel.tsx +0 -95
- package/src/helpers/getApiFilterKey.ts +0 -5
package/src/scss/variables.scss
CHANGED
|
@@ -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
|
|
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',
|
|
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<
|
|
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 {
|
|
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:
|
|
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
|
-
|
|
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
|
package/src/types/APIFilter.ts
CHANGED
package/src/types/ConfigRow.ts
CHANGED
|
@@ -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
|
package/src/types/Dashboard.ts
CHANGED
|
@@ -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 {
|
|
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,
|
|
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
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
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,
|
|
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' | '
|
|
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
|