@cdc/dashboard 4.24.12-2 → 4.25.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 (30) hide show
  1. package/dist/cdcdashboard.js +67156 -65645
  2. package/examples/private/bird-flu-2.json +440 -0
  3. package/examples/private/bird-flu.json +413 -0
  4. package/examples/private/exposure-source-h5-data.csv +26 -0
  5. package/index.html +2 -6
  6. package/package.json +9 -9
  7. package/src/CdcDashboardComponent.tsx +12 -4
  8. package/src/_stories/Dashboard.stories.tsx +32 -0
  9. package/src/_stories/_mock/data-bite-dash-test.json +1 -0
  10. package/src/_stories/_mock/data-bite-dash-test_1.json +1 -0
  11. package/src/_stories/_mock/data-bite-dash-test_1_1.json +1 -0
  12. package/src/_stories/_mock/data-bite-dash-test_1_1_1.json +1 -0
  13. package/src/components/CollapsibleVisualizationRow.tsx +2 -2
  14. package/src/components/Column.tsx +12 -1
  15. package/src/components/DashboardFilters/DashboardFilters.tsx +4 -4
  16. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +1 -3
  17. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +1 -1
  18. package/src/components/DashboardFilters/dashboardfilter.styles.css +2 -0
  19. package/src/components/ExpandCollapseButtons.tsx +1 -1
  20. package/src/components/Header/Header.tsx +1 -2
  21. package/src/components/MultiConfigTabs/MultiConfigTabs.tsx +2 -2
  22. package/src/components/MultiConfigTabs/MultiTabs.tsx +1 -1
  23. package/src/components/VisualizationRow.tsx +2 -2
  24. package/src/components/Widget.tsx +9 -3
  25. package/src/helpers/apiFilterHelpers.ts +1 -1
  26. package/src/index.tsx +1 -0
  27. package/src/scss/main.scss +1 -12
  28. package/src/store/dashboard.actions.ts +2 -2
  29. package/src/store/dashboard.reducer.ts +17 -8
  30. package/src/types/DashboardConfig.ts +2 -0
@@ -37,10 +37,21 @@ const Column = ({ data, rowIdx, colIdx }) => {
37
37
  classNames.push('column--populated')
38
38
  }
39
39
 
40
+ const handleTitle = config => {
41
+ if (!config) return
42
+ if (config.type === 'map') return config.general.title
43
+ if (config.type === 'markup-include') return config.contentEditor?.title
44
+ return config.title
45
+ }
46
+
40
47
  return (
41
48
  <div className={classNames.join(' ')} ref={drop}>
42
49
  {widget ? (
43
- <Widget widgetConfig={{ rowIdx, colIdx, ...widget }} type={widget.visualizationType ?? widget.general?.geoType} />
50
+ <Widget
51
+ title={handleTitle(widget)}
52
+ widgetConfig={{ rowIdx, colIdx, ...widget }}
53
+ type={widget.visualizationType ?? widget.general?.geoType}
54
+ />
44
55
  ) : (
45
56
  <p className='builder-column__text'>
46
57
  Drag and drop <br /> visualization
@@ -122,12 +122,12 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
122
122
  )
123
123
  }
124
124
 
125
- const formGroupClass = `form-group mr-3 mb-1${loading ? ' loading-filter' : ''}`
125
+ const formGroupClass = `form-group me-4 mb-1${loading ? ' loading-filter' : ''}`
126
126
 
127
127
  return (
128
128
  <div className={formGroupClass} key={`${label}-filtersection-${filterIndex}`}>
129
129
  {label && (
130
- <label className='font-weight-bold mt-1 mb-0' htmlFor={`filter-${filterIndex}`}>
130
+ <label className='font-weight-bold mb-2' htmlFor={`filter-${filterIndex}`}>
131
131
  {label}
132
132
  </label>
133
133
  )}
@@ -143,8 +143,8 @@ const DashboardFilters: React.FC<DashboardFilterProps> = ({
143
143
  />
144
144
  ) : filter.filterStyle === FILTER_STYLE.nestedDropdown ? (
145
145
  <NestedDropdown
146
- activeGroup={filter.active as string}
147
- activeSubGroup={_key ? filter.subGrouping?.active : activeSubGroupValue}
146
+ activeGroup={(filter.queuedActive?.[0] || filter.active) as string}
147
+ activeSubGroup={_key ? filter.queuedActive?.[1] || filter.subGrouping?.active : activeSubGroupValue}
148
148
  filterIndex={filterIndex}
149
149
  options={_key ? getNestedDropdownOptions(apiFilterDropdowns[_key]) : nestedOptions}
150
150
  listLabel={label}
@@ -40,7 +40,7 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
40
40
  Number
41
41
  )
42
42
  return config.dashboard.sharedFilters
43
- .map<[number, string]>(({ key }, i) => [i, key])
43
+ ?.map<[number, string]>(({ key }, i) => [i, key])
44
44
  .filter(([filterIndex]) => !sharedFilterIndexes.includes(filterIndex)) // filter out already added filters
45
45
  .map(([filterIndex, filterName]) => (
46
46
  <option key={filterIndex} value={filterIndex}>{`${filterIndex} - ${filterName}`}</option>
@@ -274,9 +274,7 @@ const DashboardFiltersEditor: React.FC<DashboardFitlersEditorProps> = ({ vizConf
274
274
  </select>
275
275
  </label>
276
276
  ) : (
277
-
278
277
  <button onClick={() => setCanAddExisting(true)} className='btn btn-primary full-width mt-2'>
279
-
280
278
  Add Existing Dashboard Filter
281
279
  </button>
282
280
  )}
@@ -226,7 +226,7 @@ const FilterEditor: React.FC<FilterEditorProps> = ({ filter, config, updateFilte
226
226
  </label>
227
227
  {filter.filterStyle === FILTER_STYLE.dropdown && (
228
228
  <label>
229
- <span className='mr-1'>Show Dropdown</span>
229
+ <span className='me-1'>Show Dropdown</span>
230
230
  <input
231
231
  type='checkbox'
232
232
  checked={filter.showDropdown}
@@ -2,6 +2,8 @@
2
2
  :is(label) {
3
3
  margin-bottom: 0;
4
4
  margin-top: 0.5rem;
5
+ font-size: var(--filter-label-font-size);
6
+ font-weight: 700;
5
7
  }
6
8
  .btn {
7
9
  /* this is the height that is defined for the .form-control class in _forms.scss in bootstrap. */
@@ -9,7 +9,7 @@ const ExpandCollapseButtons: React.FC<ExpandCollapseButtonsProps> = ({ setAllExp
9
9
  <button className='btn expand-collapse-buttons' onClick={() => setAllExpanded(false)}>
10
10
  - Collapse All
11
11
  </button>
12
- <button className='btn expand-collapse-buttons mr-2' onClick={() => setAllExpanded(true)}>
12
+ <button className='btn expand-collapse-buttons me-2' onClick={() => setAllExpanded(true)}>
13
13
  + Expand All
14
14
  </button>
15
15
  </div>
@@ -6,7 +6,6 @@ import './index.scss'
6
6
  import MultiConfigTabs from '../MultiConfigTabs'
7
7
  import { Tab } from '../../types/Tab'
8
8
  import _ from 'lodash'
9
- import { getVizRowColumnLocator } from '../../helpers/getVizRowColumnLocator'
10
9
 
11
10
  type HeaderProps = {
12
11
  back?: any
@@ -29,7 +28,7 @@ const Header = (props: HeaderProps) => {
29
28
  // the Widget component will do a data fetch if no data is available for the visualization
30
29
  // this is intended to help visualization developers.
31
30
  type SampleData = Record<string, { sample: boolean }> & Object[]
32
- if (Object.values(data).some((d: SampleData) => d.sample)) {
31
+ if (Object.values(data).some((d: SampleData) => d?.sample)) {
33
32
  const sampleDataRemoved = Object.keys(data).reduce((acc, key) => {
34
33
  if ((data[key] as SampleData).sample) {
35
34
  acc[key] = []
@@ -86,7 +86,7 @@ const Tab = ({ name, handleClick, tabs, index, active }) => {
86
86
  ) : (
87
87
  <>
88
88
  {name}
89
- <button className='btn btn-danger border-0 ml-1' onClick={handleRemove}>
89
+ <button className='btn btn-danger border-0 ms-1' onClick={handleRemove}>
90
90
  X
91
91
  </button>
92
92
  </>
@@ -117,7 +117,7 @@ const MultiConfigTabs = () => {
117
117
 
118
118
  if (!config.multiDashboards) return null
119
119
  return (
120
- <ul className='nav nav-tabs multi-config-tabs'>
120
+ <ul className='nav nav-tabs multi-config-tabs mb-4'>
121
121
  {tabs.map((tab, index) => (
122
122
  <Tab
123
123
  key={tab + index}
@@ -21,7 +21,7 @@ const MultiTabs = () => {
21
21
 
22
22
  if (!config.multiDashboards) return null
23
23
  return (
24
- <ul className='nav nav-tabs multi-config-tabs'>
24
+ <ul className='nav nav-tabs multi-config-tabs mb-4'>
25
25
  {tabs.map((tab, index) => (
26
26
  <li key={tab + index} className='nav-item'>
27
27
  <a
@@ -3,7 +3,6 @@ import React, { useContext, useMemo } from 'react'
3
3
  import Toggle from './Toggle'
4
4
  import _ from 'lodash'
5
5
  import { ConfigRow } from '../types/ConfigRow'
6
- import CdcChart from '@cdc/chart/src/CdcChart'
7
6
  import CdcDataBite from '@cdc/data-bite/src/CdcDataBite'
8
7
  import CdcMap from '@cdc/map/src/CdcMap'
9
8
  import CdcWaffleChart from '@cdc/waffle-chart/src/CdcWaffleChart'
@@ -18,6 +17,7 @@ import FootnotesStandAlone from '@cdc/core/components/Footnotes/FootnotesStandAl
18
17
  import CollapsibleVisualizationRow from './CollapsibleVisualizationRow'
19
18
  import { DashboardFilters } from '../types/DashboardFilters'
20
19
  import { hasDashboardApplyBehavior } from '../helpers/hasDashboardApplyBehavior'
20
+ import CdcChart from '@cdc/chart/src/CdcChartComponent'
21
21
 
22
22
  type VisualizationWrapperProps = {
23
23
  allExpanded: boolean
@@ -160,7 +160,7 @@ const VisualizationRow: React.FC<VizRowProps> = ({
160
160
  <div
161
161
  key={`vis__${index}__${colIndex}`}
162
162
  className={`col-12 col-md-${col.width}${!shouldShow ? ' d-none' : ''}${
163
- hideVisualization ? ' hide-parent-visualization' : ' mt-5 p-1'
163
+ hideVisualization ? ' hide-parent-visualization' : ' mb-4'
164
164
  }`}
165
165
  >
166
166
  {row.toggle && !hideVisualization && (
@@ -33,12 +33,13 @@ const labelHash = {
33
33
 
34
34
  type WidgetConfig = AnyVisualization & { rowIdx: number; colIdx: number }
35
35
  type WidgetProps = {
36
+ title: string
36
37
  widgetConfig?: WidgetConfig
37
38
  addVisualization?: Function
38
39
  type: string
39
40
  }
40
41
 
41
- const Widget = ({ widgetConfig, addVisualization, type }: WidgetProps) => {
42
+ const Widget = ({ title, widgetConfig, addVisualization, type }: WidgetProps) => {
42
43
  const { overlay } = useGlobalContext()
43
44
  const { config, data } = useContext(DashboardContext)
44
45
  const dispatch = useContext(DashboardDispatchContext)
@@ -74,9 +75,10 @@ const Widget = ({ widgetConfig, addVisualization, type }: WidgetProps) => {
74
75
 
75
76
  const deleteWidget = () => {
76
77
  if (!widgetConfig) return
78
+
77
79
  dispatch({
78
80
  type: 'DELETE_WIDGET',
79
- payload: { rowIdx: widgetConfig.rowIdx, colIdx: widgetConfig.colIdx, uid: widgetConfig.uid }
81
+ payload: { uid: widgetConfig.uid as string }
80
82
  })
81
83
  }
82
84
 
@@ -102,7 +104,10 @@ const Widget = ({ widgetConfig, addVisualization, type }: WidgetProps) => {
102
104
 
103
105
  const editWidget = () => {
104
106
  if (!widgetConfig) return
105
- dispatch({ type: 'UPDATE_VISUALIZATION', payload: { vizKey: widgetConfig.uid, configureData: { editing: true } } })
107
+ dispatch({
108
+ type: 'UPDATE_VISUALIZATION',
109
+ payload: { vizKey: widgetConfig.uid as string, configureData: { editing: true } }
110
+ })
106
111
  loadSampleData()
107
112
  }
108
113
 
@@ -156,6 +161,7 @@ const Widget = ({ widgetConfig, addVisualization, type }: WidgetProps) => {
156
161
  )}
157
162
  {iconHash[type]}
158
163
  <span>{labelHash[type]}</span>
164
+ <span>{title}</span>
159
165
  {widgetConfig?.newViz && type !== 'dashboardFilters' && (
160
166
  <span onClick={editWidget} className='config-needed'>
161
167
  Configuration needed
@@ -152,7 +152,7 @@ export const setAutoLoadDefaultValue = (
152
152
  if (!sharedFilter.active) {
153
153
  sharedFilter.active = defaultQueryParamValue || defaultValue
154
154
  } else {
155
- const currentOption = dropdownOptions.find(option => option.value === sharedFilter.active)
155
+ const currentOption = dropdownOptions.find(option => option.value == sharedFilter.active) // loose equality required: 2017 should equal '2017'
156
156
  sharedFilter.active = currentOption ? currentOption.value : defaultValue
157
157
  }
158
158
  }
package/src/index.tsx CHANGED
@@ -2,6 +2,7 @@ import React from 'react'
2
2
  import ReactDOM from 'react-dom/client'
3
3
 
4
4
  import MultiDashboardWrapper from './CdcDashboard'
5
+ import '@cdc/core/styles/cove-main.scss'
5
6
  import './coreStyles_dashboard.scss'
6
7
 
7
8
  let isEditor = window.location.href.includes('editor=true')
@@ -138,7 +138,6 @@
138
138
  }
139
139
 
140
140
  .btn {
141
-
142
141
  // Expand and Collapse Buttons for Multiviz Dashboard
143
142
  &.expand-collapse-buttons {
144
143
  background-color: var(--lightestGray);
@@ -163,13 +162,6 @@
163
162
  margin: 15px 0 0;
164
163
  }
165
164
 
166
- .data-table-container {
167
- margin: 20px 0 0;
168
- &.download-link-above {
169
- margin: 0;
170
- }
171
- }
172
-
173
165
  .collapsable-multiviz-container {
174
166
  position: relative;
175
167
  border: var(--lightGray) 1px solid;
@@ -193,8 +185,7 @@
193
185
  position: relative;
194
186
  }
195
187
  @include breakpoint(xs) {
196
- $font-small: 0.7em;
197
- font-size: $font-small + 0.2em;
188
+ font-size: 0.9em;
198
189
  }
199
190
  }
200
191
  .data-table-heading {
@@ -283,8 +274,6 @@
283
274
  }
284
275
 
285
276
  .cdc-dashboard-inner-container {
286
- margin: 1em;
287
-
288
277
  &.is-editor {
289
278
  margin-top: 7em;
290
279
  }
@@ -9,12 +9,12 @@ import { SharedFilter } from '../types/SharedFilter'
9
9
  type ADD_FOOTNOTE = Action<'ADD_FOOTNOTE', { id: string; rowIndex: number; config: Footnotes }>
10
10
  type ADD_VISUALIZATION = Action<'ADD_VISUALIZATION', { rowIdx: number; colIdx: number; newViz: AnyVisualization }>
11
11
  type APPLY_CONFIG = Action<'APPLY_CONFIG', [Config, Object?]>
12
- type DELETE_WIDGET = Action<'DELETE_WIDGET', { rowIdx: number; colIdx: number; uid: string }>
12
+ type DELETE_WIDGET = Action<'DELETE_WIDGET', { uid: string }>
13
13
  type MOVE_VISUALIZATION = Action<
14
14
  'MOVE_VISUALIZATION',
15
15
  { rowIdx: number; colIdx: number; widget: AnyVisualization & { rowIdx: number; colIdx: number } }
16
16
  >
17
- type SET_CONFIG = Action<'SET_CONFIG', Partial<Config>>
17
+ type SET_CONFIG = Action<'SET_CONFIG', Partial<Config> & { activeDashboard?: number }>
18
18
  type UPDATE_CONFIG = Action<'UPDATE_CONFIG', [Config, Object?]>
19
19
  type SET_DATA = Action<'SET_DATA', Record<string, any[]>>
20
20
  type SET_LOADING = Action<'SET_LOADING', boolean>
@@ -4,20 +4,20 @@ 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
- import { DashboardConfig } from '../types/DashboardConfig'
7
+ import { Dashboard } from '../types/Dashboard'
8
8
  import { ConfigRow } from '../types/ConfigRow'
9
9
  import { AnyVisualization } from '@cdc/core/types/Visualization'
10
10
  import { initialState } from '../DashboardContext'
11
11
 
12
12
  type BlankMultiConfig = {
13
- dashboard: Partial<DashboardConfig>
13
+ dashboard: Partial<Dashboard>
14
14
  rows: Partial<ConfigRow>[]
15
15
  visualizations: Record<string, Object>
16
16
  table: Object
17
17
  }
18
18
 
19
19
  const createBlankDashboard: () => BlankMultiConfig = () => ({
20
- dashboard: {},
20
+ dashboard: { sharedFilters: [] },
21
21
  rows: [{ columns: [{ width: 12 }] }],
22
22
  visualizations: {},
23
23
  table: {
@@ -71,7 +71,12 @@ const reducer = (state: DashboardState, action: DashboardActions): DashboardStat
71
71
  return { ...initialState, config, filteredData, data }
72
72
  }
73
73
  case 'SET_CONFIG': {
74
- return { ...state, config: { ...state.config, ...action.payload } }
74
+ if (
75
+ action.payload.activeDashboard === undefined ||
76
+ state.config.activeDashboard === action.payload.activeDashboard
77
+ ) {
78
+ return { ...state, config: { ...state.config, ...action.payload } }
79
+ } else return state // ignore SET_CONFIG calls that have the wrong activeDashboard due to async api fetching
75
80
  }
76
81
  case 'SET_DATA': {
77
82
  return { ...state, data: action.payload }
@@ -203,11 +208,9 @@ const reducer = (state: DashboardState, action: DashboardActions): DashboardStat
203
208
  return { ...state, config: { ...state.config, rows: newRows } }
204
209
  }
205
210
  case 'DELETE_WIDGET': {
206
- const { rowIdx, colIdx, uid } = action.payload
211
+ const { uid } = action.payload
207
212
  const newRows = _.cloneDeep(state.config.rows)
208
- newRows[rowIdx].columns[colIdx].widget = null
209
213
  const newVisualizations = _.cloneDeep(state.config.visualizations)
210
- delete newVisualizations[uid]
211
214
  const newSharedFilters = _.cloneDeep(state.config.dashboard.sharedFilters)
212
215
  if (newSharedFilters && newSharedFilters.length > 0) {
213
216
  newSharedFilters.forEach(sharedFilter => {
@@ -216,13 +219,19 @@ const reducer = (state: DashboardState, action: DashboardActions): DashboardStat
216
219
  }
217
220
  })
218
221
  }
222
+
223
+ const filteredRows = _.map(newRows, row => ({
224
+ ...row,
225
+ columns: _.filter(row.columns, column => column.widget !== uid)
226
+ }))
227
+
219
228
  return {
220
229
  ...state,
221
230
  config: {
222
231
  ...state.config,
223
232
  dashboard: { ...state.config.dashboard, sharedFilters: newSharedFilters },
224
233
  visualizations: newVisualizations,
225
- rows: newRows
234
+ rows: filteredRows
226
235
  }
227
236
  }
228
237
  }
@@ -5,6 +5,7 @@ import { ConfigRow } from './ConfigRow'
5
5
  import { AnyVisualization } from '@cdc/core/types/Visualization'
6
6
  import { Table } from '@cdc/core/types/Table'
7
7
  import { Dashboard } from './Dashboard'
8
+ import { Version } from '@cdc/core/types/Version'
8
9
 
9
10
  export type DashboardConfig = DataSet & {
10
11
  dashboard: Dashboard
@@ -18,4 +19,5 @@ export type DashboardConfig = DataSet & {
18
19
  runtime: Runtime
19
20
  downloadImageButton: boolean
20
21
  downloadPdfButton: boolean
22
+ version: Version
21
23
  }