@cdc/dashboard 4.25.5-1 → 4.25.6-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.
@@ -1,80 +1,93 @@
1
- import _ from 'lodash'
2
- import { MultiDashboardConfig } from '../types/MultiDashboard'
3
- import DataTransform from '@cdc/core/helpers/DataTransform'
4
- import { getApplicableFilters } from './getFilteredData'
5
- import { filterData } from './filterData'
6
- import Footnotes from '@cdc/core/types/Footnotes'
7
-
8
- const transform = new DataTransform()
9
-
10
- export const getFootnotesVizConfig = (vizKey: string, rowNumber: number, config: MultiDashboardConfig) => {
11
- const visualizationConfig = _.cloneDeep(config.visualizations[vizKey])
12
-
13
- const data = config.datasets[visualizationConfig.dataKey]?.data
14
- const dataColumns = data?.length ? Object.keys(data[0]) : []
15
- const filters = (getApplicableFilters(config.dashboard, rowNumber) || []).filter(filter =>
16
- dataColumns.includes(filter.columnName)
17
- )
18
- if (filters.length) {
19
- visualizationConfig.formattedData = filterData(filters, data)
20
- }
21
- visualizationConfig.data = data
22
- return visualizationConfig as Footnotes
23
- }
24
-
25
- export const getVizConfig = (
26
- visualizationKey: string,
27
- rowNumber: number,
28
- config: MultiDashboardConfig,
29
- data: Object,
30
- filteredData?: Object
31
- ) => {
32
- if (rowNumber === undefined) return {}
33
- const visualizationConfig = _.cloneDeep(config.visualizations[visualizationKey])
34
- const rowData = config.rows[rowNumber]
35
- if (rowData.footnotesId && rowData.footnotesId === visualizationKey) {
36
- // return the footnotes visualization config with filtered data
37
- return getFootnotesVizConfig(visualizationKey, rowNumber, config)
38
- }
39
- if (rowData?.dataKey) {
40
- // data configured on the row
41
- Object.assign(visualizationConfig, _.pick(rowData, ['dataKey', 'dataDescription', 'formattedData', 'data']))
42
- }
43
-
44
- if (visualizationConfig.table && config.dashboard.sharedFilters.length) {
45
- // Download CSV button needs to know to include shared filter columns
46
- const sharedFilterColumns = config.dashboard.sharedFilters.reduce((acc, filter) => {
47
- if (!filter.usedBy?.length || filter.usedBy?.includes(visualizationKey)) {
48
- const apiFilter = filter.apiFilter
49
- const colName = apiFilter?.textSelector || apiFilter?.valueSelector || filter.columnName
50
- acc.push(colName)
51
- const subGrouping =
52
- apiFilter?.subgroupTextSelector || apiFilter?.subgroupValueSelector || filter.subGrouping?.columnName
53
- if (subGrouping) {
54
- acc.push(subGrouping)
55
- }
56
- }
57
- return acc
58
- }, [])
59
- visualizationConfig.table.sharedFilterColumns = sharedFilterColumns
60
- }
61
-
62
- if (visualizationConfig.formattedData) visualizationConfig.originalFormattedData = visualizationConfig.formattedData
63
- const filteredVizData = filteredData?.[rowNumber] ?? filteredData?.[visualizationKey]
64
-
65
- if (filteredVizData) {
66
- visualizationConfig.data = filteredVizData || []
67
- if (visualizationConfig.formattedData) {
68
- visualizationConfig.formattedData = visualizationConfig.data
69
- }
70
- } else {
71
- const dataKey = visualizationConfig.dataKey || 'backwards-compatibility'
72
- visualizationConfig.data = data[dataKey] || []
73
- if (visualizationConfig.formattedData) {
74
- visualizationConfig.formattedData =
75
- transform.developerStandardize(visualizationConfig.data, visualizationConfig.dataDescription) ||
76
- visualizationConfig.data
77
- }
78
- }
79
- return visualizationConfig
80
- }
1
+ import _ from 'lodash'
2
+ import { MultiDashboardConfig } from '../types/MultiDashboard'
3
+ import DataTransform from '@cdc/core/helpers/DataTransform'
4
+ import { filterData } from './filterData'
5
+ import { AnyVisualization } from '@cdc/core/types/Visualization'
6
+
7
+ const transform = new DataTransform()
8
+
9
+ export const getFootnotesVizConfig = (vizConfig: AnyVisualization, config: MultiDashboardConfig) => {
10
+ if (!vizConfig?.footnotes) return vizConfig
11
+
12
+ const data = config.datasets[vizConfig.footnotes.dataKey]?.data ?? []
13
+
14
+ const filters = config?.dashboard?.sharedFilters
15
+ if (filters.length === 0) return vizConfig
16
+ vizConfig.footnotes.data = filters.length ? filterData(filters, data) : data
17
+
18
+ return vizConfig
19
+ }
20
+
21
+ export const getVizConfig = (
22
+ visualizationKey: string,
23
+ rowNumber: number,
24
+ config: MultiDashboardConfig,
25
+ data: Object,
26
+ filteredData?: Object,
27
+ filteredDataOverride?: Object[],
28
+ multiVizColumn?: string
29
+ ): AnyVisualization => {
30
+ if (rowNumber === undefined) return {} as AnyVisualization
31
+ const visualizationConfig = _.cloneDeep(config.visualizations[visualizationKey])
32
+ const rowData = config.rows[rowNumber]
33
+ if (visualizationConfig.footnotes?.dataKey) {
34
+ visualizationConfig.footnotes.data = config.datasets[visualizationConfig.footnotes.dataKey]?.data
35
+ }
36
+ if (rowData?.dataKey) {
37
+ // data configured on the row
38
+ Object.assign(visualizationConfig, _.pick(rowData, ['dataKey', 'dataDescription', 'formattedData', 'data']))
39
+ }
40
+
41
+ if (visualizationConfig.table && config.dashboard.sharedFilters.length) {
42
+ // Download CSV button needs to know to include shared filter columns
43
+ const sharedFilterColumns = config.dashboard.sharedFilters.reduce((acc, filter) => {
44
+ if (!filter.usedBy?.length || filter.usedBy?.includes(visualizationKey)) {
45
+ const apiFilter = filter.apiFilter
46
+ const colName = apiFilter?.textSelector || apiFilter?.valueSelector || filter.columnName
47
+ acc.push(colName)
48
+ const subGrouping =
49
+ apiFilter?.subgroupTextSelector || apiFilter?.subgroupValueSelector || filter.subGrouping?.columnName
50
+ if (subGrouping) {
51
+ acc.push(subGrouping)
52
+ }
53
+ }
54
+ return acc
55
+ }, [])
56
+ visualizationConfig.table.sharedFilterColumns = sharedFilterColumns
57
+ }
58
+
59
+ if (visualizationConfig.formattedData) visualizationConfig.originalFormattedData = visualizationConfig.formattedData
60
+ const filteredVizData = filteredData?.[rowNumber] ?? filteredData?.[visualizationKey]
61
+
62
+ if (filteredVizData) {
63
+ visualizationConfig.data = filteredVizData || []
64
+ if (visualizationConfig.formattedData) {
65
+ visualizationConfig.formattedData = visualizationConfig.data
66
+ }
67
+ } else {
68
+ const dataKey = visualizationConfig.dataKey || 'backwards-compatibility'
69
+ visualizationConfig.data = data[dataKey] || []
70
+ if (visualizationConfig.formattedData) {
71
+ visualizationConfig.formattedData =
72
+ transform.developerStandardize(visualizationConfig.data, visualizationConfig.dataDescription) ||
73
+ visualizationConfig.data
74
+ }
75
+ }
76
+
77
+ if (filteredDataOverride) {
78
+ visualizationConfig.data = filteredDataOverride
79
+ }
80
+
81
+ if (visualizationConfig.footnotes) {
82
+ const visConfigWithFootnotes = getFootnotesVizConfig(visualizationConfig, config)
83
+ if (multiVizColumn && filteredDataOverride) {
84
+ const vizCategory = filteredDataOverride[0][multiVizColumn]
85
+ // the multiViz filtering filtering is applied after the dashboard filters
86
+ const categoryFootnote = visConfigWithFootnotes.footnotes.data.filter(d => d[multiVizColumn] === vizCategory)
87
+ visConfigWithFootnotes.footnotes.data = categoryFootnote
88
+ }
89
+ return visConfigWithFootnotes
90
+ }
91
+
92
+ return visualizationConfig as AnyVisualization
93
+ }
@@ -6,6 +6,5 @@ export const getVizRowColumnLocator = (rows: ConfigRow[]): Record<string, { row:
6
6
  curr.columns?.forEach((column, columnIndex) => {
7
7
  if (column.widget !== undefined) acc[column.widget] = { row: index, column: columnIndex }
8
8
  })
9
- if (curr.footnotesId) acc[curr.footnotesId] = { row: index, column: 0 }
10
9
  return acc
11
10
  }, {})
@@ -31,8 +31,11 @@ type GetDatasetKeysParams = Pick<DashboardConfig, 'visualizations' | 'datasets'
31
31
  export const getDatasetKeys = ({ visualizations, datasets, rows }: GetDatasetKeysParams): string[] => {
32
32
  const vizDataKeys = Object.values(visualizations).map(viz => viz.dataKey)
33
33
  const rowDataKeys = rows.map(row => row.dataKey)
34
+ const footnoteDataKeys = Object.values(visualizations)
35
+ .map(viz => viz.footnotes?.dataKey)
36
+ .filter(Boolean)
34
37
  // ensure to only load datasets for the specific dashboard tab.
35
- const datasetsUsedByDashboard = _.uniq([...vizDataKeys, ...rowDataKeys])
38
+ const datasetsUsedByDashboard = _.uniq([...vizDataKeys, ...rowDataKeys, ...footnoteDataKeys])
36
39
  return Object.keys(datasets).filter(datasetKey => datasetsUsedByDashboard.includes(datasetKey))
37
40
  }
38
41
 
@@ -111,17 +114,11 @@ export const filterUsedByDataUrl = (
111
114
  ) => {
112
115
  if (!filter.usedBy || !filter.usedBy.length) return true
113
116
  const vizUsingFilters = filter.usedBy?.map(vizOrRowKey => visualizations[vizOrRowKey] || rows[vizOrRowKey])
114
- // push any footnotes which are using the filter also
115
- const vizRowLookup = getVizRowColumnLocator(rows) // ensure we have the footnotesId in the rows
116
- filter.usedBy?.forEach(vizOrRowKey => {
117
- const vizLookup = vizRowLookup[vizOrRowKey] // if found vizOrRowKey is a viz key
118
- const row = rows[vizLookup?.row || vizOrRowKey]
119
- if (row?.footnotesId) {
120
- // if the widget is using the filter and the widget is on this row and the row has a footnoteId
121
- // then the footnote's endpoint should be filtered by the filter
122
- vizUsingFilters.push(visualizations[row.footnotesId])
123
- }
124
- })
125
117
 
126
- return vizUsingFilters?.some(viz => viz?.dataKey === datasetKey)
118
+ return vizUsingFilters?.some(viz => {
119
+ const usedByViz = viz?.dataKey === datasetKey
120
+ // datasetKey might be a key to a dynamic footnotes URL
121
+ const usedByVizFootnote = viz?.footnotes?.dataKey === datasetKey
122
+ return usedByViz || usedByVizFootnote
123
+ })
127
124
  }
@@ -1,64 +1,61 @@
1
- import type { DashboardConfig as Config } from '../types/DashboardConfig'
2
- import { type Action } from '@cdc/core/types/Action'
3
- import { Tab } from '../types/Tab'
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'
8
-
9
- type ADD_FOOTNOTE = Action<'ADD_FOOTNOTE', { id: string; rowIndex: number; config: Footnotes }>
10
- type ADD_VISUALIZATION = Action<'ADD_VISUALIZATION', { rowIdx: number; colIdx: number; newViz: AnyVisualization }>
11
- type APPLY_CONFIG = Action<'APPLY_CONFIG', [Config, Object?]>
12
- type DELETE_WIDGET = Action<'DELETE_WIDGET', { uid: string }>
13
- type MOVE_VISUALIZATION = Action<
14
- 'MOVE_VISUALIZATION',
15
- { rowIdx: number; colIdx: number; widget: AnyVisualization & { rowIdx: number; colIdx: number } }
16
- >
17
- type SET_CONFIG = Action<'SET_CONFIG', Partial<Config> & { activeDashboard?: number }>
18
- type UPDATE_CONFIG = Action<'UPDATE_CONFIG', [Config, Object?]>
19
- type SET_DATA = Action<'SET_DATA', Record<string, any[]>>
20
- type SET_LOADING = Action<'SET_LOADING', boolean>
21
- type SET_PREVIEW = Action<'SET_PREVIEW', boolean>
22
- type SET_FILTERED_DATA = Action<'SET_FILTERED_DATA', Object>
23
- type SET_SHARED_FILTERS = Action<'SET_SHARED_FILTERS', SharedFilter[]>
24
- type SET_TAB_SELECTED = Action<'SET_TAB_SELECTED', Tab>
25
- type RENAME_DASHBOARD_TAB = Action<'RENAME_DASHBOARD_TAB', { current: string; new: string }>
26
- type INITIALIZE_MULTIDASHBOARDS = Action<'INITIALIZE_MULTIDASHBOARDS', undefined>
27
- type REMOVE_MULTIDASHBOARD_AT_INDEX = Action<'REMOVE_MULTIDASHBOARD_AT_INDEX', number>
28
- type REORDER_MULTIDASHBOARDS = Action<'REORDER_MULTIDASHBOARDS', { currentIndex: number; newIndex: number }>
29
- type ADD_NEW_DASHBOARD = Action<'ADD_NEW_DASHBOARD', undefined>
30
- type SAVE_CURRENT_CHANGES = Action<'SAVE_CURRENT_CHANGES', undefined>
31
- type SWITCH_CONFIG = Action<'SWITCH_CONFIG', number>
32
- type TOGGLE_ROW = Action<'TOGGLE_ROW', { rowIndex: number; colIndex: number }>
33
- type RESET_VISUALIZATION = Action<'RESET_VISUALIZATION', { vizKey: string }>
34
- type UPDATE_VISUALIZATION = Action<'UPDATE_VISUALIZATION', { vizKey: string; configureData: Partial<AnyVisualization> }>
35
- type UPDATE_ROW = Action<'UPDATE_ROW', { rowIndex: number; rowData: Partial<ConfigRow> }>
36
- type UPDATE_TOGGLE_NAME = Action<'UPDATE_TOGGLE_NAME', { rowIndex: number; columnIndex: number; toggleName: string }>
37
-
38
- type DashboardActions =
39
- | ADD_FOOTNOTE
40
- | ADD_VISUALIZATION
41
- | APPLY_CONFIG
42
- | ADD_NEW_DASHBOARD
43
- | DELETE_WIDGET
44
- | MOVE_VISUALIZATION
45
- | SET_CONFIG
46
- | UPDATE_CONFIG
47
- | REMOVE_MULTIDASHBOARD_AT_INDEX
48
- | RENAME_DASHBOARD_TAB
49
- | REORDER_MULTIDASHBOARDS
50
- | SAVE_CURRENT_CHANGES
51
- | SET_DATA
52
- | SET_LOADING
53
- | SET_PREVIEW
54
- | SET_FILTERED_DATA
55
- | SET_SHARED_FILTERS
56
- | SET_TAB_SELECTED
57
- | SWITCH_CONFIG
58
- | INITIALIZE_MULTIDASHBOARDS
59
- | TOGGLE_ROW
60
- | RESET_VISUALIZATION
61
- | UPDATE_VISUALIZATION
62
- | UPDATE_ROW
63
- | UPDATE_TOGGLE_NAME
64
- export default DashboardActions
1
+ import type { DashboardConfig as Config } from '../types/DashboardConfig'
2
+ import { type Action } from '@cdc/core/types/Action'
3
+ import { Tab } from '../types/Tab'
4
+ import { ConfigRow } from '../types/ConfigRow'
5
+ import { AnyVisualization } from '@cdc/core/types/Visualization'
6
+ import { SharedFilter } from '../types/SharedFilter'
7
+
8
+ type ADD_VISUALIZATION = Action<'ADD_VISUALIZATION', { rowIdx: number; colIdx: number; newViz: AnyVisualization }>
9
+ type APPLY_CONFIG = Action<'APPLY_CONFIG', [Config, Object?]>
10
+ type DELETE_WIDGET = Action<'DELETE_WIDGET', { uid: string }>
11
+ type MOVE_VISUALIZATION = Action<
12
+ 'MOVE_VISUALIZATION',
13
+ { rowIdx: number; colIdx: number; widget: AnyVisualization & { rowIdx: number; colIdx: number } }
14
+ >
15
+ type SET_CONFIG = Action<'SET_CONFIG', Partial<Config> & { activeDashboard?: number }>
16
+ type UPDATE_CONFIG = Action<'UPDATE_CONFIG', [Config, Object?]>
17
+ type SET_DATA = Action<'SET_DATA', Record<string, any[]>>
18
+ type SET_LOADING = Action<'SET_LOADING', boolean>
19
+ type SET_PREVIEW = Action<'SET_PREVIEW', boolean>
20
+ type SET_FILTERED_DATA = Action<'SET_FILTERED_DATA', Object>
21
+ type SET_SHARED_FILTERS = Action<'SET_SHARED_FILTERS', SharedFilter[]>
22
+ type SET_TAB_SELECTED = Action<'SET_TAB_SELECTED', Tab>
23
+ type RENAME_DASHBOARD_TAB = Action<'RENAME_DASHBOARD_TAB', { current: string; new: string }>
24
+ type INITIALIZE_MULTIDASHBOARDS = Action<'INITIALIZE_MULTIDASHBOARDS', undefined>
25
+ type REMOVE_MULTIDASHBOARD_AT_INDEX = Action<'REMOVE_MULTIDASHBOARD_AT_INDEX', number>
26
+ type REORDER_MULTIDASHBOARDS = Action<'REORDER_MULTIDASHBOARDS', { currentIndex: number; newIndex: number }>
27
+ type ADD_NEW_DASHBOARD = Action<'ADD_NEW_DASHBOARD', undefined>
28
+ type SAVE_CURRENT_CHANGES = Action<'SAVE_CURRENT_CHANGES', undefined>
29
+ type SWITCH_CONFIG = Action<'SWITCH_CONFIG', number>
30
+ type TOGGLE_ROW = Action<'TOGGLE_ROW', { rowIndex: number; colIndex: number }>
31
+ type RESET_VISUALIZATION = Action<'RESET_VISUALIZATION', { vizKey: string }>
32
+ type UPDATE_VISUALIZATION = Action<'UPDATE_VISUALIZATION', { vizKey: string; configureData: Partial<AnyVisualization> }>
33
+ type UPDATE_ROW = Action<'UPDATE_ROW', { rowIndex: number; rowData: Partial<ConfigRow> }>
34
+ type UPDATE_TOGGLE_NAME = Action<'UPDATE_TOGGLE_NAME', { rowIndex: number; columnIndex: number; toggleName: string }>
35
+
36
+ type DashboardActions =
37
+ | ADD_VISUALIZATION
38
+ | APPLY_CONFIG
39
+ | ADD_NEW_DASHBOARD
40
+ | DELETE_WIDGET
41
+ | MOVE_VISUALIZATION
42
+ | SET_CONFIG
43
+ | UPDATE_CONFIG
44
+ | REMOVE_MULTIDASHBOARD_AT_INDEX
45
+ | RENAME_DASHBOARD_TAB
46
+ | REORDER_MULTIDASHBOARDS
47
+ | SAVE_CURRENT_CHANGES
48
+ | SET_DATA
49
+ | SET_LOADING
50
+ | SET_PREVIEW
51
+ | SET_FILTERED_DATA
52
+ | SET_SHARED_FILTERS
53
+ | SET_TAB_SELECTED
54
+ | SWITCH_CONFIG
55
+ | INITIALIZE_MULTIDASHBOARDS
56
+ | TOGGLE_ROW
57
+ | RESET_VISUALIZATION
58
+ | UPDATE_VISUALIZATION
59
+ | UPDATE_ROW
60
+ | UPDATE_TOGGLE_NAME
61
+ export default DashboardActions
@@ -39,17 +39,6 @@ export type DashboardState = {
39
39
 
40
40
  const reducer = (state: DashboardState, action: DashboardActions): DashboardState => {
41
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 {
46
- ...state,
47
- config: saveMultiChanges(
48
- { ...state.config, rows: newRows, visualizations: { ...state.config.visualizations, [id]: config } },
49
- state.config.activeDashboard
50
- )
51
- }
52
- }
53
42
  case 'ADD_NEW_DASHBOARD': {
54
43
  const currentMultiDashboards = state.config.multiDashboards
55
44
  const label = 'New Dashboard ' + (currentMultiDashboards.length + 1)
@@ -16,5 +16,4 @@ export type ConfigRow = {
16
16
  toggle?: boolean
17
17
  equalHeight?: boolean
18
18
  multiVizColumn?: string
19
- footnotesId?: string // id for the footnotes in the vizConfig section
20
19
  } & ConfigureData
@@ -1,4 +1,4 @@
1
- import { DataSet } from './DataSet'
1
+ import { DataSet } from '@cdc/core/types/DataSet'
2
2
  import { SharedFilter } from './SharedFilter'
3
3
 
4
4
  export type Dashboard = {
@@ -1,6 +1,6 @@
1
1
  import { Series } from '@cdc/core/types/Series'
2
2
  import { Runtime } from '@cdc/core/types/Runtime'
3
- import { DataSet } from './DataSet'
3
+ import { DataSet } from '@cdc/core/types/DataSet'
4
4
  import { ConfigRow } from './ConfigRow'
5
5
  import { AnyVisualization } from '@cdc/core/types/Visualization'
6
6
  import { Table } from '@cdc/core/types/Table'
@@ -1,12 +0,0 @@
1
- import { ConfigureData } from '@cdc/core/types/ConfigureData'
2
-
3
- export type DataSet = ConfigureData & {
4
- dataFileFormat?: string
5
- dataFileName?: string
6
- dataFileSize?: number
7
- preview?: boolean
8
- dataUrl: string
9
- runtimeDataUrl: string
10
- dataFileSourceType: string
11
- loadQueryParam?: string // fetched from the browser's query string and appended to the dataUrl on load.
12
- }