@cdc/dashboard 4.23.3 → 4.23.5

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/index.html CHANGED
@@ -1,31 +1,29 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
6
+ <style>
7
+ body {
8
+ margin: 0 auto !important;
9
+ display: flex;
10
+ flex-direction: column;
11
+ justify-content: center;
12
+ min-height: unset !important;
13
+ }
3
14
 
4
- <head>
5
- <meta charset="utf-8" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
7
- <style>
8
- body {
9
- margin: 0 auto !important;
10
- display: flex;
11
- flex-direction: column;
12
- justify-content: center;
13
- min-height: unset !important;
14
- }
15
-
16
- .react-container+.react-container {
17
- margin-top: 3rem;
18
- }
19
- </style>
20
- </head>
21
-
22
- <body>
23
- <!-- <div class="react-container" data-config="/examples/default.json"></div> -->
24
- <!-- <div class="react-container" data-config="/examples/default-multi-dataset.json"></div> -->
25
- <div class="react-container" data-config="/examples/default-filter-control.json"></div>
26
- <!-- <div class="react-container" data-config="/examples/private/totals.json"></div> -->
27
- <!-- <div class="react-container" data-config="/examples/private/totals-two.json"></div> -->
28
- <script type="module" src="./src/index.jsx"></script>
29
- </body>
15
+ .react-container + .react-container {
16
+ margin-top: 3rem;
17
+ }
18
+ </style>
19
+ </head>
30
20
 
21
+ <body>
22
+ <div class="react-container" data-config="/examples/default.json"></div>
23
+ <!-- <div class="react-container" data-config="/examples/default-multi-dataset.json"></div> -->
24
+ <!-- <div class="react-container" data-config="/examples/default-filter-control.json"></div> -->
25
+ <!-- <div class="react-container" data-config="/examples/private/totals.json"></div> -->
26
+ <!-- <div class="react-container" data-config="/examples/private/totals-two.json"></div> -->
27
+ <script type="module" src="./src/index.jsx"></script>
28
+ </body>
31
29
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdc/dashboard",
3
- "version": "4.23.3",
3
+ "version": "4.23.5",
4
4
  "description": "React component for combining multiple visualizations into a single dashboard",
5
5
  "moduleName": "CdcDashboard",
6
6
  "main": "dist/cdcdashboard",
@@ -25,13 +25,13 @@
25
25
  },
26
26
  "license": "Apache-2.0",
27
27
  "dependencies": {
28
- "@cdc/chart": "^4.23.3",
29
- "@cdc/core": "^4.23.3",
30
- "@cdc/data-bite": "^4.23.3",
31
- "@cdc/filtered-text": "^4.23.3",
32
- "@cdc/map": "^4.23.3",
33
- "@cdc/markup-include": "^4.23.3",
34
- "@cdc/waffle-chart": "^4.23.3",
28
+ "@cdc/chart": "^4.23.5",
29
+ "@cdc/core": "^4.23.5",
30
+ "@cdc/data-bite": "^4.23.5",
31
+ "@cdc/filtered-text": "^4.23.5",
32
+ "@cdc/map": "^4.23.5",
33
+ "@cdc/markup-include": "^4.23.5",
34
+ "@cdc/waffle-chart": "^4.23.5",
35
35
  "html-react-parser": "^3.0.8",
36
36
  "js-base64": "^2.5.2",
37
37
  "papaparse": "^5.3.0",
@@ -47,5 +47,5 @@
47
47
  "react": "^18.2.0",
48
48
  "react-dom": "^18.2.0"
49
49
  },
50
- "gitHead": "6fa3b11db159d38538f18023fe70b67a29e7d327"
50
+ "gitHead": "34add3436994ca3cf13e51f313add4d70377f53e"
51
51
  }
@@ -11,7 +11,6 @@ import { HTML5Backend } from 'react-dnd-html5-backend'
11
11
  import parse from 'html-react-parser'
12
12
 
13
13
  import fetchRemoteData from '@cdc/core/helpers/fetchRemoteData'
14
- import cacheBustingString from '@cdc/core/helpers/cacheBustingString'
15
14
  import { GlobalContextProvider } from '@cdc/core/components/GlobalContext'
16
15
  import ConfigContext from './ConfigContext'
17
16
 
@@ -101,7 +100,7 @@ const VisualizationsPanel = () => (
101
100
  </div>
102
101
  )
103
102
 
104
- export default function CdcDashboard({ configUrl = '', config: configObj = undefined, isEditor = false, setConfig: setParentConfig }) {
103
+ export default function CdcDashboard({ configUrl = '', config: configObj = undefined, isEditor = false, isDebug = false, setConfig: setParentConfig }) {
105
104
  const [config, setConfig] = useState(configObj ?? {})
106
105
  const [data, setData] = useState([])
107
106
  const [filteredData, setFilteredData] = useState()
@@ -115,25 +114,106 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
115
114
 
116
115
  const transform = new DataTransform()
117
116
 
117
+ const getFormattedData = (data, dataDescription) => {
118
+ if (data && dataDescription) {
119
+ try {
120
+ let formattedData = transform.autoStandardize(data)
121
+ formattedData = transform.developerStandardize(data, dataDescription)
122
+ return formattedData
123
+ } catch (e) {
124
+ return data
125
+ }
126
+ }
127
+
128
+ return data
129
+ }
130
+
118
131
  const processData = async config => {
119
132
  let dataset = config.formattedData || config.data
120
133
 
121
134
  if (config.dataUrl) {
122
- dataset = fetchRemoteData(`${config.dataUrl}?v=${cacheBustingString()}`)
123
-
124
- if (dataset && config.dataDescription) {
125
- try {
126
- dataset = transform.autoStandardize(data)
127
- dataset = transform.developerStandardize(data, config.dataDescription)
128
- } catch (e) {
129
- //Data not able to be standardized, leave as is
130
- }
131
- }
135
+ dataset = await fetchRemoteData(`${config.dataUrl}`)
136
+
137
+ dataset = getFormattedData(dataset, config.dataDescription)
132
138
  }
133
139
 
134
140
  return dataset
135
141
  }
136
142
 
143
+ const reloadURLData = async () => {
144
+ if (config.datasets) {
145
+ let newData = { ...data }
146
+ let newDatasets = { ...config.datasets }
147
+ let datasetsNeedsUpdate = false
148
+ let datasetKeys = Object.keys(config.datasets)
149
+ for (let i = 0; i < datasetKeys.length; i++) {
150
+ const dataset = config.datasets[datasetKeys[i]]
151
+ if (dataset.dataUrl && config.dashboard && config.dashboard.sharedFilters) {
152
+ const dataUrl = new URL(dataset.runtimeDataUrl || dataset.dataUrl)
153
+ let qsParams = Object.fromEntries(new URLSearchParams(dataUrl.search))
154
+
155
+ let isUpdateNeeded = false
156
+
157
+ config.dashboard.sharedFilters.forEach(filter => {
158
+ if (filter.type === 'url' && qsParams[filter.queryParameter] !== decodeURIComponent(filter.active)) {
159
+ qsParams[filter.queryParameter] = filter.active
160
+ isUpdateNeeded = true
161
+ }
162
+ })
163
+
164
+ if (!isUpdateNeeded) return
165
+
166
+ let dataUrlFinal = `${dataUrl.origin}${dataUrl.pathname}${Object.keys(qsParams)
167
+ .map((param, i) => {
168
+ let qs = i === 0 ? '?' : '&'
169
+ qs += param + '='
170
+ qs += qsParams[param]
171
+ return qs
172
+ })
173
+ .join('')}`
174
+
175
+ let newDataset = await fetchRemoteData(`${dataUrlFinal}`)
176
+
177
+ if (newDataset && dataset.dataDescription) {
178
+ try {
179
+ newDataset = transform.autoStandardize(newDataset)
180
+ newDataset = transform.developerStandardize(newDataset, dataset.dataDescription)
181
+ } catch (e) {
182
+ //Data not able to be standardized, leave as is
183
+ }
184
+ }
185
+
186
+ newDatasets[datasetKeys[i]].runtimeDataUrl = dataUrlFinal
187
+ newData[datasetKeys[i]] = newDataset
188
+ datasetsNeedsUpdate = true
189
+ }
190
+ }
191
+
192
+ if (datasetsNeedsUpdate) {
193
+ setData(newData)
194
+
195
+ let newFilteredData = {}
196
+ let newConfig = { ...config }
197
+ Object.keys(config.visualizations).forEach(key => {
198
+ let dataKey = config.visualizations[key].dataKey
199
+
200
+ let applicableFilters = config.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.usedBy && sharedFilter.usedBy.indexOf(key) !== -1)
201
+ if (applicableFilters.length > 0) {
202
+ newFilteredData[key] = filterData(applicableFilters, newData[dataKey])
203
+ }
204
+
205
+ if (newData[dataKey]) {
206
+ newConfig.visualizations[key].formattedData = newData[dataKey]
207
+ }
208
+ })
209
+ setFilteredData(newFilteredData)
210
+
211
+ newConfig.datasets = newDatasets
212
+ setConfig(newConfig)
213
+ }
214
+ }
215
+ }
216
+
137
217
  const loadConfig = async () => {
138
218
  let response = configObj || (await (await fetch(configUrl)).json())
139
219
  let newConfig = { ...defaults, ...response }
@@ -145,6 +225,14 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
145
225
  datasets[key] = await processData(response.datasets[key])
146
226
  })
147
227
  )
228
+
229
+ Object.keys(newConfig.visualizations).forEach(vizKey => {
230
+ newConfig.visualizations[vizKey].formattedData = datasets[newConfig.visualizations[vizKey].dataKey]
231
+ })
232
+
233
+ Object.keys(datasets).forEach(key => {
234
+ newConfig.datasets[key].data = datasets[key]
235
+ })
148
236
  } else {
149
237
  let dataKey = newConfig.dataFileName || 'backwards-compatibility'
150
238
  datasets[dataKey] = await processData(response)
@@ -193,7 +281,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
193
281
  let add = true
194
282
 
195
283
  filters.forEach(filter => {
196
- if (row[filter.columnName] !== filter.active) {
284
+ if (filter.type !== 'url' && row[filter.columnName] != filter.active) {
197
285
  add = false
198
286
  }
199
287
  })
@@ -222,7 +310,9 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
222
310
  if (applicableFilters.length > 0) {
223
311
  const visualization = newConfig.visualizations[visualizationKey]
224
312
 
225
- newFilteredData[visualizationKey] = filterData(applicableFilters, visualization.formattedData || data[visualization.dataKey])
313
+ const formattedData = visualization.dataDescription ? getFormattedData(data[visualization.dataKey] || visualization.data, visualization.dataDescription) : undefined
314
+
315
+ newFilteredData[visualizationKey] = filterData(applicableFilters, formattedData || data[visualization.dataKey])
226
316
  }
227
317
  })
228
318
 
@@ -283,7 +373,11 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
283
373
  let applicableFilters = newConfig.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.usedBy && sharedFilter.usedBy.indexOf(visualizationKey) !== -1)
284
374
 
285
375
  if (applicableFilters.length > 0) {
286
- newFilteredData[visualizationKey] = filterData(applicableFilters, newConfig.visualizations[visualizationKey].formattedData || newConfig.visualizations[visualizationKey].data || (dataOverride || data)[newConfig.visualizations[visualizationKey].dataKey])
376
+ const visualization = newConfig.visualizations[visualizationKey]
377
+
378
+ const formattedData = getFormattedData(visualization.data, visualization.dataDescription)
379
+
380
+ newFilteredData[visualizationKey] = filterData(applicableFilters, formattedData || visualization.data || (dataOverride || data)[visualization.dataKey])
287
381
  }
288
382
  })
289
383
  }
@@ -307,6 +401,10 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
307
401
  }
308
402
  }, [config])
309
403
 
404
+ useEffect(() => {
405
+ reloadURLData()
406
+ }, [JSON.stringify(config.dashboard ? config.dashboard.sharedFilters : undefined)])
407
+
310
408
  const updateChildConfig = (visualizationKey, newConfig) => {
311
409
  let updatedConfig = { ...config }
312
410
 
@@ -328,24 +426,28 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
328
426
  Object.keys(config.visualizations).forEach(key => {
329
427
  let applicableFilters = dashboardConfig.sharedFilters.filter(sharedFilter => sharedFilter.usedBy && sharedFilter.usedBy.indexOf(key) !== -1)
330
428
  if (applicableFilters.length > 0) {
331
- newFilteredData[key] = filterData(applicableFilters, config.visualizations[key].formattedData || data[config.visualizations[key].dataKey])
429
+ const visualization = config.visualizations[key]
430
+
431
+ const formattedData = visualization.dataDescription ? getFormattedData(data[config.visualizations[key].dataKey] || visualization.data, visualization.dataDescription) : undefined
432
+
433
+ newFilteredData[key] = filterData(applicableFilters, formattedData || data[config.visualizations[key].dataKey])
332
434
  }
333
435
  })
334
436
 
335
437
  setFilteredData(newFilteredData)
336
438
  }
337
439
 
338
- const announceChange = text => { }
440
+ const announceChange = text => {}
339
441
 
340
442
  return config.dashboard.sharedFilters.map((singleFilter, index) => {
341
- if (!singleFilter.showDropdown) return <></>
443
+ if (singleFilter.type !== 'url' && !singleFilter.showDropdown) return <></>
342
444
 
343
445
  const values = []
344
446
 
345
447
  singleFilter.values.forEach((filterOption, index) => {
346
448
  values.push(
347
449
  <option key={`${singleFilter.key}-option-${index}`} value={filterOption}>
348
- {filterOption}
450
+ {singleFilter.labels ? singleFilter.labels[filterOption] || filterOption : filterOption}
349
451
  </option>
350
452
  )
351
453
  })
@@ -436,7 +538,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
436
538
  body = (
437
539
  <>
438
540
  <Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor='Chart' />
439
- <CdcChart key={visualizationKey} config={visualizationConfig} isEditor={true} setConfig={updateConfig} setSharedFilter={setsSharedFilter ? setSharedFilter : undefined} isDashboard={true} />
541
+ <CdcChart key={visualizationKey} config={visualizationConfig} isEditor={true} isDebug={isDebug} setConfig={updateConfig} setSharedFilter={setsSharedFilter ? setSharedFilter : undefined} isDashboard={true} />
440
542
  </>
441
543
  )
442
544
  break
@@ -444,7 +546,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
444
546
  body = (
445
547
  <>
446
548
  <Header tabSelected={tabSelected} setTabSelected={setTabSelected} back={back} subEditor='Map' />
447
- <CdcMap key={visualizationKey} config={visualizationConfig} isEditor={true} setConfig={updateConfig} setSharedFilter={setsSharedFilter ? setSharedFilter : undefined} setSharedFilterValue={setSharedFilterValue} isDashboard={true} />
549
+ <CdcMap key={visualizationKey} config={visualizationConfig} isEditor={true} isDebug={isDebug} setConfig={updateConfig} setSharedFilter={setsSharedFilter ? setSharedFilter : undefined} setSharedFilterValue={setSharedFilterValue} isDashboard={true} />
448
550
  </>
449
551
  )
450
552
  break
@@ -551,7 +653,11 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
551
653
 
552
654
  const setsSharedFilter = config.dashboard.sharedFilters && config.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.setBy === col.widget).length > 0
553
655
  const setSharedFilterValue = setsSharedFilter ? config.dashboard.sharedFilters.filter(sharedFilter => sharedFilter.setBy === col.widget)[0].active : undefined
554
- const tableLink = <a href={`#data-table-${visualizationConfig.dataKey}`}>{visualizationConfig.dataKey} (Go to Table)</a>
656
+ const tableLink = (
657
+ <a href={`#data-table-${visualizationConfig.dataKey}`} className='margin-left-href'>
658
+ {visualizationConfig.dataKey} (Go to Table)
659
+ </a>
660
+ )
555
661
 
556
662
  return (
557
663
  <React.Fragment key={`vis__${index}__${colIndex}`}>
@@ -566,7 +672,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
566
672
  }}
567
673
  setSharedFilter={setsSharedFilter ? setSharedFilter : undefined}
568
674
  isDashboard={true}
569
- link={config.table && config.table.show && config.datasets ? tableLink : undefined}
675
+ link={config.table && config.table.show && config.datasets && visualizationConfig.table && visualizationConfig.table.showDataTableLink ? tableLink : undefined}
570
676
  />
571
677
  )}
572
678
  {visualizationConfig.type === 'map' && (
@@ -580,7 +686,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
580
686
  setSharedFilter={setsSharedFilter ? setSharedFilter : undefined}
581
687
  setSharedFilterValue={setSharedFilterValue}
582
688
  isDashboard={true}
583
- link={config.table && config.table.show && config.datasets ? tableLink : undefined}
689
+ link={config.table && config.table.show && config.datasets && visualizationConfig.table && visualizationConfig.table.showDataTableLink ? tableLink : undefined}
584
690
  />
585
691
  )}
586
692
  {visualizationConfig.type === 'data-bite' && (
@@ -603,7 +709,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
603
709
  updateChildConfig(col.widget, newConfig)
604
710
  }}
605
711
  isDashboard={true}
606
- link={config.table && config.table.show && config.datasets ? tableLink : undefined}
712
+ link={config.table && config.table.show && config.datasets && visualizationConfig.table && visualizationConfig.table.showDataTableLink ? tableLink : undefined}
607
713
  />
608
714
  )}
609
715
  {visualizationConfig.type === 'markup-include' && (
@@ -666,7 +772,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
666
772
  config.dashboard.sharedFilters.forEach(sharedFilter => {
667
773
  let allMatch = true
668
774
  vizKeysUsingDataset.forEach(visualizationKey => {
669
- if (sharedFilter.usedBy.indexOf(visualizationKey) === -1) {
775
+ if (sharedFilter.usedBy && sharedFilter.usedBy.indexOf(visualizationKey) === -1) {
670
776
  allMatch = false
671
777
  }
672
778
  })
@@ -685,7 +791,7 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
685
791
 
686
792
  return (
687
793
  <div className='multi-table-container' id={`data-table-${datasetKey}`} key={`data-table-${datasetKey}`}>
688
- <DataTable data={filteredTableData || config.datasets[datasetKey].data} downloadData={config.datasets[datasetKey].data} dataFileSourceType={dataFileSourceType} datasetKey={datasetKey} config={config} imageRef={imageId}></DataTable>
794
+ <DataTable data={filteredTableData || config.datasets[datasetKey].data || []} downloadData={config.datasets[datasetKey].data} dataFileSourceType={dataFileSourceType} datasetKey={datasetKey} config={config} imageRef={imageId}></DataTable>
689
795
  </div>
690
796
  )
691
797
  })}
@@ -704,7 +810,8 @@ export default function CdcDashboard({ configUrl = '', config: configObj = undef
704
810
  updateConfig,
705
811
  setParentConfig,
706
812
  setPreview,
707
- outerContainerRef
813
+ outerContainerRef,
814
+ isDebug
708
815
  }
709
816
 
710
817
  const dashboardContainerClasses = ['cdc-open-viz-module', 'type-dashboard', `${currentViewport}`]