@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.
@@ -11,49 +11,45 @@ import CdcFilteredText from '@cdc/filtered-text/src/CdcFilteredText'
11
11
  import DashboardSharedFilters, { APIFilterDropdowns } from './DashboardFilters'
12
12
  import { DashboardContext } from '../DashboardContext'
13
13
  import { ViewPort } from '@cdc/core/types/ViewPort'
14
- import { getFootnotesVizConfig, getVizConfig } from '../helpers/getVizConfig'
14
+ import { getVizConfig } from '../helpers/getVizConfig'
15
15
  import { TableConfig } from '@cdc/core/components/DataTable/types/TableConfig'
16
- import FootnotesStandAlone from '@cdc/core/components/Footnotes/FootnotesStandAlone'
17
16
  import CollapsibleVisualizationRow from './CollapsibleVisualizationRow'
18
17
  import { DashboardFilters } from '../types/DashboardFilters'
19
18
  import { hasDashboardApplyBehavior } from '../helpers/hasDashboardApplyBehavior'
20
19
  import CdcChart from '@cdc/chart/src/CdcChartComponent'
20
+ import ExpandCollapseButtons from './ExpandCollapseButtons'
21
+ import { ChartConfig } from '@cdc/chart/src/types/ChartConfig'
21
22
 
22
23
  type VisualizationWrapperProps = {
23
24
  allExpanded: boolean
24
25
  children: React.ReactNode
25
26
  currentViewport: ViewPort
26
27
  groupName: string
27
- hideVisualization: boolean
28
- row: ConfigRow
28
+ className: string
29
+ collapsible?: boolean
29
30
  }
30
31
 
31
32
  const VisualizationWrapper: React.FC<VisualizationWrapperProps> = ({
32
33
  allExpanded,
33
34
  currentViewport,
34
35
  groupName,
35
- hideVisualization,
36
- row,
36
+ collapsible,
37
+ className,
37
38
  children
38
39
  }) => {
39
- return hideVisualization ? (
40
- <></>
41
- ) : row.expandCollapseAllButtons ? (
42
- <div className='collapsable-multiviz-container'>
43
- <CollapsibleVisualizationRow
44
- allExpanded={allExpanded}
45
- fontSize={'26px'}
46
- groupName={groupName}
47
- currentViewport={currentViewport}
48
- >
49
- {children}
50
- </CollapsibleVisualizationRow>
40
+ return (
41
+ <div className={className}>
42
+ {collapsible ? (
43
+ <CollapsibleVisualizationRow allExpanded={allExpanded} groupName={groupName} currentViewport={currentViewport}>
44
+ {children}
45
+ </CollapsibleVisualizationRow>
46
+ ) : (
47
+ <>
48
+ {groupName !== '' ? <h3>{groupName}</h3> : <></>}
49
+ {children}
50
+ </>
51
+ )}
51
52
  </div>
52
- ) : (
53
- <>
54
- {groupName !== '' ? <h3>{groupName}</h3> : <></>}
55
- {children}
56
- </>
57
53
  )
58
54
  }
59
55
 
@@ -69,6 +65,7 @@ type VizRowProps = {
69
65
  apiFilterDropdowns: APIFilterDropdowns
70
66
  currentViewport: ViewPort
71
67
  isLastRow: boolean
68
+ setAllExpanded?: (expanded: boolean) => void
72
69
  }
73
70
 
74
71
  const VisualizationRow: React.FC<VizRowProps> = ({
@@ -82,7 +79,8 @@ const VisualizationRow: React.FC<VizRowProps> = ({
82
79
  updateChildConfig,
83
80
  apiFilterDropdowns,
84
81
  currentViewport,
85
- isLastRow
82
+ isLastRow,
83
+ setAllExpanded
86
84
  }) => {
87
85
  const { config, filteredData: dashboardFilteredData, data: rawData } = useContext(DashboardContext)
88
86
  const [toggledRow, setToggled] = React.useState<number>(0)
@@ -99,22 +97,15 @@ const VisualizationRow: React.FC<VizRowProps> = ({
99
97
  }
100
98
  }, [config.activeDashboard, toggledRow])
101
99
 
102
- const footnotesConfig = useMemo(() => {
103
- if (row.footnotesId) {
104
- const footnoteConfig = getFootnotesVizConfig(row.footnotesId, index, config)
105
- if (row.multiVizColumn && filteredDataOverride) {
106
- const vizCategory = filteredDataOverride[0][row.multiVizColumn]
107
- // the multiViz filtering filtering is applied after the dashboard filters
108
- const categoryFootnote = footnoteConfig.formattedData.filter(d => d[row.multiVizColumn] === vizCategory)
109
- footnoteConfig.formattedData = categoryFootnote
110
- } else {
111
- footnoteConfig.formattedData = dashboardFilteredData[row.footnotesId]
112
- }
113
-
114
- return footnoteConfig
115
- }
116
- return null
117
- }, [config, row, rawData, dashboardFilteredData])
100
+ const _data = dashboardFilteredData[index] || row.formattedData || []
101
+ const dataGroups =
102
+ row.multiVizColumn &&
103
+ _data.reduce((acc, dataRow) => {
104
+ const groupKey = dataRow[row.multiVizColumn]
105
+ if (!acc[groupKey]) acc[groupKey] = []
106
+ acc[groupKey].push(dataRow)
107
+ return acc
108
+ }, {})
118
109
 
119
110
  const applyButtonNotClicked = (vizConfig: DashboardFilters): boolean => {
120
111
  const dashboardFilters = Object.values(config.visualizations).filter(
@@ -134,6 +125,39 @@ const VisualizationRow: React.FC<VizRowProps> = ({
134
125
  }
135
126
  return false
136
127
  }
128
+
129
+ if (dataGroups) {
130
+ return (
131
+ <React.Fragment key={`row__${index}`}>
132
+ {/* Expand/Collapse All */}
133
+ {!inNoDataState && row.expandCollapseAllButtons === true && (
134
+ <ExpandCollapseButtons setAllExpanded={setAllExpanded} />
135
+ )}
136
+ {Object.keys(dataGroups).map(groupName => {
137
+ const dataValue = dataGroups[groupName]
138
+ const _row = _.cloneDeep(row) // clone the row to avoid mutating the original row
139
+ _row.multiVizColumn = undefined // reset the multiVizColumn to avoid passing it to the child components
140
+ return (
141
+ <VisualizationRow
142
+ key={`row__${index}__${groupName}`}
143
+ allExpanded={allExpanded}
144
+ filteredDataOverride={dataValue}
145
+ groupName={groupName}
146
+ row={_row}
147
+ rowIndex={index}
148
+ setSharedFilter={setSharedFilter}
149
+ updateChildConfig={updateChildConfig}
150
+ apiFilterDropdowns={apiFilterDropdowns}
151
+ currentViewport={currentViewport}
152
+ inNoDataState={inNoDataState}
153
+ isLastRow={isLastRow}
154
+ />
155
+ )
156
+ })}
157
+ </React.Fragment>
158
+ )
159
+ }
160
+
137
161
  return (
138
162
  <div className={`row${row.equalHeight ? ' equal-height' : ''}${row.toggle ? ' toggle' : ''}`} key={`row__${index}`}>
139
163
  {row.toggle && !inNoDataState && (
@@ -143,13 +167,17 @@ const VisualizationRow: React.FC<VizRowProps> = ({
143
167
  if (col.width) {
144
168
  if (!col.widget) return <div key={`row__${index}__col__${colIndex}`} className={`col col-${col.width}`}></div>
145
169
 
146
- const visualizationConfig = getVizConfig(col.widget, index, config, rawData, dashboardFilteredData)
147
- if (filteredDataOverride) {
148
- visualizationConfig.data = filteredDataOverride
149
- if (visualizationConfig.formattedData) {
150
- visualizationConfig.formattedData = filteredDataOverride
151
- }
152
- }
170
+ const visualizationConfig = getVizConfig(
171
+ col.widget,
172
+ index,
173
+ config,
174
+ rawData,
175
+ dashboardFilteredData,
176
+ filteredDataOverride,
177
+ row.multiVizColumn
178
+ )
179
+
180
+ const { type, sharedFilterIndexes, filterBehavior, table, dataKey } = visualizationConfig
153
181
 
154
182
  const setsSharedFilter =
155
183
  config.dashboard.sharedFilters &&
@@ -158,188 +186,137 @@ const VisualizationRow: React.FC<VizRowProps> = ({
158
186
  ? config.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.setBy === col.widget)[0].active
159
187
  : undefined
160
188
  const tableLink = (
161
- <a href={`#data-table-${visualizationConfig.dataKey}`} className='margin-left-href'>
162
- {visualizationConfig.dataKey} (Go to Table)
189
+ <a href={`#data-table-${dataKey}`} className='margin-left-href'>
190
+ {dataKey} (Go to Table)
163
191
  </a>
164
192
  )
165
193
 
166
194
  const hideVisualization =
167
195
  inNoDataState &&
168
- visualizationConfig.filterBehavior !== 'Apply Button' &&
169
- (visualizationConfig.type !== 'dashboardFilters' || applyButtonNotClicked(visualizationConfig))
196
+ filterBehavior !== 'Apply Button' &&
197
+ (type !== 'dashboardFilters' || applyButtonNotClicked(visualizationConfig))
170
198
 
171
199
  const shouldShow = row.toggle === undefined || (row.toggle && show[colIndex])
172
200
 
173
201
  const hiddenDashboardFilters =
174
- visualizationConfig.type === 'dashboardFilters' &&
175
- visualizationConfig.sharedFilterIndexes &&
176
- visualizationConfig.sharedFilterIndexes.filter(
177
- idx => config.dashboard.sharedFilters?.[idx]?.showDropdown === false
178
- ).length === visualizationConfig.sharedFilterIndexes.length
202
+ type === 'dashboardFilters' &&
203
+ sharedFilterIndexes &&
204
+ sharedFilterIndexes.filter(idx => config.dashboard.sharedFilters?.[idx]?.showDropdown === false).length ===
205
+ sharedFilterIndexes.length
179
206
  const hasMarginBottom = !isLastRow && !hiddenDashboardFilters
180
207
 
181
- return (
182
- <div
208
+ const vizWrapperClass = `col-12 col-md-${col.width}${!shouldShow ? ' d-none' : ''}${
209
+ hideVisualization ? ' hide-parent-visualization' : hasMarginBottom ? ' mb-4' : ''
210
+ }`
211
+ const link =
212
+ config.table && config.table.show && config.datasets && table && table.showDataTableLink
213
+ ? tableLink
214
+ : undefined
215
+ return hideVisualization ? null : (
216
+ <VisualizationWrapper
183
217
  key={`vis__${index}__${colIndex}`}
184
- className={`col-12 col-md-${col.width}${!shouldShow ? ' d-none' : ''}${
185
- hideVisualization ? ' hide-parent-visualization' : hasMarginBottom ? ' mb-4' : ''
186
- }`}
218
+ className={vizWrapperClass}
219
+ allExpanded={allExpanded}
220
+ currentViewport={currentViewport}
221
+ groupName={groupName}
222
+ collapsible={row.expandCollapseAllButtons}
187
223
  >
188
- <VisualizationWrapper
189
- allExpanded={allExpanded}
190
- currentViewport={currentViewport}
191
- groupName={groupName}
192
- hideVisualization={hideVisualization}
193
- row={row}
194
- >
195
- {visualizationConfig.type === 'chart' && (
196
- <CdcChart
197
- key={col.widget}
198
- config={visualizationConfig}
199
- dashboardConfig={config}
200
- isEditor={false}
201
- setConfig={newConfig => {
202
- updateChildConfig(col.widget, newConfig)
203
- }}
204
- setSharedFilter={setsSharedFilter ? setSharedFilter : undefined}
205
- isDashboard={true}
206
- link={
207
- config.table &&
208
- config.table.show &&
209
- config.datasets &&
210
- visualizationConfig.table &&
211
- visualizationConfig.table.showDataTableLink
212
- ? tableLink
213
- : undefined
214
- }
215
- configUrl={undefined}
216
- setEditing={undefined}
217
- hostname={undefined}
218
- setSharedFilterValue={undefined}
219
- />
220
- )}
221
- {visualizationConfig.type === 'map' && (
222
- <CdcMap
223
- key={col.widget}
224
- config={visualizationConfig}
225
- isEditor={false}
226
- setConfig={newConfig => {
227
- updateChildConfig(col.widget, newConfig)
228
- }}
229
- showLoader={false}
230
- setSharedFilter={setsSharedFilter ? setSharedFilter : undefined}
231
- setSharedFilterValue={setSharedFilterValue}
232
- isDashboard={true}
233
- link={
234
- config.table &&
235
- config.table.show &&
236
- config.datasets &&
237
- visualizationConfig.table &&
238
- visualizationConfig.table.showDataTableLink
239
- ? tableLink
240
- : undefined
241
- }
242
- />
243
- )}
244
- {visualizationConfig.type === 'data-bite' && (
245
- <CdcDataBite
246
- key={col.widget}
247
- config={visualizationConfig}
248
- isEditor={false}
249
- setConfig={newConfig => {
250
- updateChildConfig(col.widget, newConfig)
251
- }}
252
- isDashboard={true}
253
- />
254
- )}
255
- {visualizationConfig.type === 'waffle-chart' && (
256
- <CdcWaffleChart
257
- key={col.widget}
258
- config={visualizationConfig}
259
- isEditor={false}
260
- setConfig={newConfig => {
261
- updateChildConfig(col.widget, newConfig)
262
- }}
263
- isDashboard={true}
264
- configUrl={
265
- config.table &&
266
- config.table.show &&
267
- config.datasets &&
268
- visualizationConfig.table &&
269
- visualizationConfig.table.showDataTableLink
270
- ? tableLink
271
- : undefined
272
- }
273
- />
274
- )}
275
- {visualizationConfig.type === 'markup-include' && (
276
- <CdcMarkupInclude
277
- key={col.widget}
278
- config={visualizationConfig}
279
- configUrl={undefined}
280
- isDashboard={true}
281
- isEditor={false}
282
- setConfig={newConfig => {
283
- updateChildConfig(col.widget, newConfig)
284
- }}
285
- />
286
- )}
287
- {visualizationConfig.type === 'filtered-text' && (
288
- <CdcFilteredText
289
- key={col.widget}
290
- config={visualizationConfig}
291
- isEditor={false}
292
- setConfig={newConfig => {
293
- updateChildConfig(col.widget, newConfig)
294
- }}
295
- isDashboard={true}
296
- configUrl={undefined}
297
- />
298
- )}
299
- {visualizationConfig.type === 'dashboardFilters' && (
300
- <DashboardSharedFilters
301
- setConfig={newConfig => {
302
- updateChildConfig(col.widget, newConfig)
303
- }}
304
- key={col.widget}
305
- visualizationConfig={visualizationConfig as DashboardFilters}
306
- apiFilterDropdowns={apiFilterDropdowns}
307
- currentViewport={currentViewport}
308
- />
309
- )}
310
- {visualizationConfig.type === 'table' && (
311
- <DataTableStandAlone
312
- key={col.widget}
313
- updateConfig={newConfig => {
314
- updateChildConfig(col.widget, newConfig)
315
- }}
316
- visualizationKey={col.widget}
317
- config={visualizationConfig as TableConfig}
318
- viewport={currentViewport}
319
- />
320
- )}
321
- {visualizationConfig.type === 'footnotes' && (
322
- <FootnotesStandAlone
323
- key={col.widget}
324
- visualizationKey={col.widget}
325
- config={visualizationConfig}
326
- viewport={currentViewport}
327
- />
328
- )}
329
- </VisualizationWrapper>
330
- </div>
224
+ {type === 'chart' && (
225
+ <CdcChart
226
+ key={col.widget}
227
+ config={visualizationConfig as ChartConfig}
228
+ dashboardConfig={config}
229
+ datasets={config.datasets}
230
+ setConfig={newConfig => {
231
+ updateChildConfig(col.widget, newConfig)
232
+ }}
233
+ setSharedFilter={setsSharedFilter ? setSharedFilter : undefined}
234
+ isDashboard={true}
235
+ link={link}
236
+ />
237
+ )}
238
+ {type === 'map' && (
239
+ <CdcMap
240
+ key={col.widget}
241
+ config={visualizationConfig}
242
+ setConfig={newConfig => {
243
+ updateChildConfig(col.widget, newConfig)
244
+ }}
245
+ showLoader={false}
246
+ setSharedFilter={setsSharedFilter ? setSharedFilter : undefined}
247
+ setSharedFilterValue={setSharedFilterValue}
248
+ isDashboard={true}
249
+ link={link}
250
+ dataset={config.datasets}
251
+ />
252
+ )}
253
+ {type === 'data-bite' && (
254
+ <CdcDataBite
255
+ key={col.widget}
256
+ config={visualizationConfig}
257
+ setConfig={newConfig => {
258
+ updateChildConfig(col.widget, newConfig)
259
+ }}
260
+ isDashboard={true}
261
+ />
262
+ )}
263
+ {type === 'waffle-chart' && (
264
+ <CdcWaffleChart
265
+ key={col.widget}
266
+ config={visualizationConfig}
267
+ setConfig={newConfig => {
268
+ updateChildConfig(col.widget, newConfig)
269
+ }}
270
+ isDashboard={true}
271
+ configUrl={link}
272
+ />
273
+ )}
274
+ {type === 'markup-include' && (
275
+ <CdcMarkupInclude
276
+ key={col.widget}
277
+ config={visualizationConfig}
278
+ isDashboard={true}
279
+ setConfig={newConfig => {
280
+ updateChildConfig(col.widget, newConfig)
281
+ }}
282
+ />
283
+ )}
284
+ {type === 'filtered-text' && (
285
+ <CdcFilteredText
286
+ key={col.widget}
287
+ config={visualizationConfig}
288
+ setConfig={newConfig => {
289
+ updateChildConfig(col.widget, newConfig)
290
+ }}
291
+ isDashboard={true}
292
+ />
293
+ )}
294
+ {type === 'dashboardFilters' && (
295
+ <DashboardSharedFilters
296
+ setConfig={newConfig => {
297
+ updateChildConfig(col.widget, newConfig)
298
+ }}
299
+ key={col.widget}
300
+ visualizationConfig={visualizationConfig as DashboardFilters}
301
+ apiFilterDropdowns={apiFilterDropdowns}
302
+ currentViewport={currentViewport}
303
+ />
304
+ )}
305
+ {type === 'table' && (
306
+ <DataTableStandAlone
307
+ key={col.widget}
308
+ updateConfig={newConfig => {
309
+ updateChildConfig(col.widget, newConfig)
310
+ }}
311
+ visualizationKey={col.widget}
312
+ config={visualizationConfig as TableConfig}
313
+ viewport={currentViewport}
314
+ />
315
+ )}
316
+ </VisualizationWrapper>
331
317
  )
332
318
  }
333
- return <React.Fragment key={`vis__${index}__${colIndex}`}></React.Fragment>
334
319
  })}
335
- {row.footnotesId && !inNoDataState ? (
336
- <FootnotesStandAlone
337
- isEditor={false}
338
- visualizationKey={row.footnotesId}
339
- config={footnotesConfig}
340
- viewport={currentViewport}
341
- />
342
- ) : null}
343
320
  </div>
344
321
  )
345
322
  }