@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.
- package/LICENSE +201 -0
- package/dist/cdcdashboard.js +77779 -77245
- package/examples/special-classes.json +54340 -0
- package/package.json +9 -9
- package/src/CdcDashboardComponent.tsx +36 -214
- package/src/_stories/_mock/api-filter-map.json +1 -0
- package/src/components/CollapsibleVisualizationRow.tsx +2 -4
- package/src/components/DashboardEditors.tsx +143 -0
- package/src/components/DashboardFilters/DashboardFilters.tsx +205 -205
- package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +286 -287
- package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +198 -198
- package/src/components/Header/Header.tsx +7 -9
- package/src/components/Row.tsx +1 -24
- package/src/components/VisualizationRow.tsx +190 -213
- package/src/helpers/getVizConfig.ts +93 -80
- package/src/helpers/getVizRowColumnLocator.ts +0 -1
- package/src/helpers/reloadURLHelpers.ts +10 -13
- package/src/store/dashboard.actions.ts +61 -64
- package/src/store/dashboard.reducer.ts +0 -11
- package/src/types/ConfigRow.ts +0 -1
- package/src/types/Dashboard.ts +1 -1
- package/src/types/DashboardConfig.ts +1 -1
- package/src/types/DataSet.ts +0 -12
|
@@ -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 {
|
|
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
|
-
|
|
28
|
-
|
|
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
|
-
|
|
36
|
-
|
|
36
|
+
collapsible,
|
|
37
|
+
className,
|
|
37
38
|
children
|
|
38
39
|
}) => {
|
|
39
|
-
return
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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-${
|
|
162
|
-
{
|
|
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
|
-
|
|
169
|
-
(
|
|
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
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
-
|
|
182
|
-
|
|
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={
|
|
185
|
-
|
|
186
|
-
}
|
|
218
|
+
className={vizWrapperClass}
|
|
219
|
+
allExpanded={allExpanded}
|
|
220
|
+
currentViewport={currentViewport}
|
|
221
|
+
groupName={groupName}
|
|
222
|
+
collapsible={row.expandCollapseAllButtons}
|
|
187
223
|
>
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
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
|
}
|