@cdc/dashboard 4.26.1 → 4.26.3

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 (76) hide show
  1. package/LICENSE +201 -0
  2. package/dist/cdcdashboard-8NmHlKRI.es.js +15 -0
  3. package/dist/cdcdashboard-BPoPzKPz.es.js +6 -0
  4. package/dist/{cdcdashboard-dgT_1dIT.es.js → cdcdashboard-DQ00cQCm.es.js} +1 -20
  5. package/dist/cdcdashboard-jiQQPkty.es.js +6 -0
  6. package/dist/cdcdashboard-vr9HZwRt.es.js +6 -0
  7. package/dist/cdcdashboard.js +80971 -83096
  8. package/examples/custom/css/respiratory.css +1 -1
  9. package/examples/data/data-with-metadata.json +18 -0
  10. package/examples/default.json +492 -132
  11. package/examples/nested-dropdown.json +6985 -0
  12. package/examples/private/abc.json +467 -0
  13. package/examples/private/dash.json +12696 -0
  14. package/examples/private/inline-markup.json +775 -0
  15. package/examples/private/npcr.json +1 -0
  16. package/examples/private/recent-update.json +1456 -0
  17. package/examples/private/test.json +125407 -0
  18. package/examples/private/timeline-data.json +4994 -0
  19. package/examples/private/timeline.json +1708 -0
  20. package/examples/private/toggle.json +10137 -0
  21. package/examples/test-api-filter-reset.json +8 -4
  22. package/examples/tp5-gauges.json +196 -0
  23. package/examples/tp5-test.json +266 -0
  24. package/index.html +1 -29
  25. package/package.json +38 -40
  26. package/src/CdcDashboard.tsx +2 -1
  27. package/src/CdcDashboardComponent.tsx +47 -30
  28. package/src/_stories/Dashboard.DataSetup.stories.tsx +8 -2
  29. package/src/_stories/Dashboard.Pages.stories.tsx +22 -0
  30. package/src/_stories/Dashboard.stories.tsx +4501 -80
  31. package/src/_stories/_mock/dashboard-line-chart-angles.json +1030 -0
  32. package/src/_stories/_mock/tab-simple-filter.json +153 -0
  33. package/src/_stories/_mock/tp5-test.json +267 -0
  34. package/src/components/DashboardFilters/DashboardFilters.tsx +19 -3
  35. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +10 -4
  36. package/src/components/DashboardFilters/DashboardFiltersEditor/components/APIModal.tsx +1 -1
  37. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +6 -3
  38. package/src/components/DashboardFilters/DashboardFiltersEditor/components/NestedDropDownDashboard.tsx +13 -8
  39. package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +8 -8
  40. package/src/components/DashboardFilters/_stories/DashboardFilters.stories.tsx +1 -1
  41. package/src/components/DashboardFilters/dashboardfilter.styles.css +3 -3
  42. package/src/components/DataDesignerModal.tsx +2 -2
  43. package/src/components/Header/Header.tsx +27 -5
  44. package/src/components/Header/index.scss +1 -1
  45. package/src/components/MultiConfigTabs/multiconfigtabs.styles.css +6 -6
  46. package/src/components/Row.tsx +21 -0
  47. package/src/components/Toggle/toggle-style.css +7 -7
  48. package/src/components/VisualizationRow.tsx +42 -29
  49. package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +1 -71
  50. package/src/components/VisualizationsPanel/visualizations-panel-styles.css +2 -2
  51. package/src/components/Widget/Widget.tsx +2 -2
  52. package/src/components/Widget/widget.styles.css +12 -12
  53. package/src/data/initial-state.js +1 -1
  54. package/src/helpers/addValuesToDashboardFilters.ts +17 -11
  55. package/src/helpers/addVisualization.ts +71 -0
  56. package/src/helpers/apiFilterHelpers.ts +28 -32
  57. package/src/helpers/formatConfigBeforeSave.ts +1 -1
  58. package/src/helpers/getVizConfig.ts +13 -3
  59. package/src/helpers/iconHash.tsx +45 -36
  60. package/src/helpers/processDataLegacy.ts +19 -14
  61. package/src/helpers/tests/addValuesToDashboardFilters.test.ts +141 -44
  62. package/src/helpers/tests/addVisualization.test.ts +52 -0
  63. package/src/helpers/tests/apiFilterHelpers.test.ts +523 -420
  64. package/src/helpers/tests/formatConfigBeforeSave.test.ts +81 -1
  65. package/src/scss/editor-panel.scss +1 -1
  66. package/src/scss/main.scss +169 -41
  67. package/src/store/dashboard.reducer.ts +1 -1
  68. package/src/test/CdcDashboard.test.jsx +2 -2
  69. package/src/test/CdcDashboardComponent.test.tsx +74 -0
  70. package/src/types/FilterStyles.ts +2 -1
  71. package/tests/fixtures/dashboard-config-with-metadata.json +89 -0
  72. package/vite.config.js +7 -1
  73. package/dist/cdcdashboard-BnB1QM5d.es.js +0 -361528
  74. package/dist/cdcdashboard-Ct2SB0vL.es.js +0 -231049
  75. package/dist/cdcdashboard-D6CG2-Hb.es.js +0 -39377
  76. package/dist/cdcdashboard-MXgURbdZ.es.js +0 -39194
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest'
2
- import { cleanSharedFilters } from '../formatConfigBeforeSave'
2
+ import { cleanSharedFilters, stripConfig } from '../formatConfigBeforeSave'
3
3
  import { DashboardConfig } from '../../types/DashboardConfig'
4
4
 
5
5
  describe('cleanSharedFilters', () => {
@@ -67,3 +67,83 @@ describe('cleanSharedFilters', () => {
67
67
  expect(config.dashboard.sharedFilters).toEqual([{ id: 1, type: 'urlfilter' }])
68
68
  })
69
69
  })
70
+
71
+ describe('stripConfig', () => {
72
+ it('removes inline data for non-dashboard URL-backed configs when isEditor is false', () => {
73
+ const config = {
74
+ type: 'bar',
75
+ dataUrl: '/api/data.csv',
76
+ data: [{ value: 10 }],
77
+ runtime: { loaded: true },
78
+ formattedData: [{ value: 10 }]
79
+ }
80
+
81
+ const stripped = stripConfig(config)
82
+
83
+ expect(stripped.data).toBeUndefined()
84
+ expect(stripped.dataUrl).toBe('/api/data.csv')
85
+ expect(stripped.runtime).toBeUndefined()
86
+ expect(stripped.formattedData).toBeUndefined()
87
+ })
88
+
89
+ it('preserves inline data for non-dashboard URL-backed configs when isEditor is true', () => {
90
+ const config = {
91
+ type: 'bar',
92
+ dataUrl: '/api/data.csv',
93
+ data: [{ value: 10 }],
94
+ runtime: { loaded: true },
95
+ formattedData: [{ value: 10 }]
96
+ }
97
+
98
+ const stripped = stripConfig(config, true)
99
+
100
+ expect(stripped.data).toEqual([{ value: 10 }])
101
+ expect(stripped.dataUrl).toBe('/api/data.csv')
102
+ expect(stripped.runtime).toBeUndefined()
103
+ expect(stripped.formattedData).toBeUndefined()
104
+ })
105
+
106
+ it('removes dashboard dataset data when dataset has dataUrl and isEditor is false', () => {
107
+ const config = {
108
+ type: 'dashboard',
109
+ dashboard: { sharedFilters: [] },
110
+ datasets: {
111
+ data_1: {
112
+ dataUrl: '/api/dashboard.csv',
113
+ data: [{ a: 1 }],
114
+ formattedData: [{ a: 1 }]
115
+ }
116
+ },
117
+ visualizations: {},
118
+ rows: []
119
+ } as any
120
+
121
+ const stripped = stripConfig(config)
122
+
123
+ expect(stripped.datasets.data_1.data).toBeUndefined()
124
+ expect(stripped.datasets.data_1.formattedData).toBeUndefined()
125
+ expect(stripped.datasets.data_1.dataUrl).toBe('/api/dashboard.csv')
126
+ })
127
+
128
+ it('preserves dashboard dataset data when dataset has dataUrl and isEditor is true', () => {
129
+ const config = {
130
+ type: 'dashboard',
131
+ dashboard: { sharedFilters: [] },
132
+ datasets: {
133
+ data_1: {
134
+ dataUrl: '/api/dashboard.csv',
135
+ data: [{ a: 1 }],
136
+ formattedData: [{ a: 1 }]
137
+ }
138
+ },
139
+ visualizations: {},
140
+ rows: []
141
+ } as any
142
+
143
+ const stripped = stripConfig(config, true)
144
+
145
+ expect(stripped.datasets.data_1.data).toEqual([{ a: 1 }])
146
+ expect(stripped.datasets.data_1.formattedData).toBeUndefined()
147
+ expect(stripped.datasets.data_1.dataUrl).toBe('/api/dashboard.csv')
148
+ })
149
+ })
@@ -4,7 +4,7 @@
4
4
  // Shift down for top level Dashboard bar when in edit mode
5
5
  .layout-container,
6
6
  .editor-panel + .cdc-dashboard-inner-container,
7
- .editor-heading + .cdc-open-viz-module {
7
+ .editor-heading + .cove-visualization {
8
8
  position: relative;
9
9
  min-height: 80vh;
10
10
  }
@@ -1,13 +1,18 @@
1
- @import '@cdc/core/styles/v2/utils/breakpoints';
1
+ @import '@cdc/core/styles/utils/breakpoints';
2
2
 
3
- .cdc-open-viz-module.type-dashboard {
3
+ button.row-menu__btn[title*='Equal Height Rows'] {
4
+ margin-left: 15px;
5
+ }
6
+
7
+ .cove-visualization.type-dashboard {
4
8
  @import 'editor-panel';
5
9
  @import 'grid';
6
- .loading > div.la-ball-beat {
10
+
11
+ .loading>div.la-ball-beat {
7
12
  margin-top: 20%;
8
13
  }
9
14
 
10
- > .cove-editor__content {
15
+ >.cove-editor__content {
11
16
  width: 100% !important;
12
17
  left: 0px;
13
18
  }
@@ -19,22 +24,27 @@
19
24
  display: flex;
20
25
  width: 100vw;
21
26
  z-index: 5;
27
+
22
28
  &.sub-dashboard-viz {
23
29
  height: 3em;
24
30
  }
31
+
25
32
  .heading-1 {
26
33
  min-width: 335px;
27
34
  font-size: 1.2em;
28
35
  padding-right: 1em;
29
36
  margin: 0.5em 1em 0.5em 0;
30
37
  border-right: 1px solid black;
38
+
31
39
  &.back-to {
32
40
  display: flex;
41
+
33
42
  span {
34
43
  font-weight: bold;
35
44
  padding-right: 0.3em;
36
45
  }
37
46
  }
47
+
38
48
  input[type='text'] {
39
49
  width: 100%;
40
50
  margin-top: 10px;
@@ -43,6 +53,7 @@
43
53
 
44
54
  .heading-body {
45
55
  display: flex;
56
+ align-items: flex-start;
46
57
 
47
58
  .wrap {
48
59
  display: inline-flex;
@@ -83,6 +94,7 @@
83
94
  position: relative;
84
95
  bottom: -1px;
85
96
  border-bottom: #c7c7c7 1px solid;
97
+
86
98
  li {
87
99
  padding: 0.3em 1.5em;
88
100
  color: var(--mediumGray);
@@ -90,12 +102,14 @@
90
102
  white-space: nowrap;
91
103
  text-overflow: ellipsis;
92
104
  overflow: hidden;
105
+
93
106
  &.active {
94
107
  border-bottom-color: var(--mediumGray);
95
108
  border-bottom-style: inherit;
96
109
  border-bottom-width: 5px;
97
110
  color: var(--darkGray);
98
111
  }
112
+
99
113
  &:hover {
100
114
  border-bottom-color: var(--darkGray);
101
115
  color: var(--darkGray);
@@ -122,6 +136,7 @@
122
136
  }
123
137
 
124
138
  .btn {
139
+
125
140
  // Expand and Collapse Buttons for Multiviz Dashboard
126
141
  &.expand-collapse-buttons {
127
142
  background-color: var(--lightestGray);
@@ -139,11 +154,13 @@
139
154
  border: var(--lightGray) 1px solid;
140
155
  clear: both;
141
156
  margin-bottom: 20px;
157
+
142
158
  .multi-visualiation-heading {
143
159
  position: relative;
144
160
  background: var(--lightestGray);
145
161
  padding: 0.5em 0.7em;
146
162
  cursor: pointer;
163
+
147
164
  svg {
148
165
  position: absolute;
149
166
  height: 100%;
@@ -156,10 +173,12 @@
156
173
  z-index: 2;
157
174
  position: relative;
158
175
  }
176
+
159
177
  @include breakpoint(xs) {
160
178
  font-size: 0.9em;
161
179
  }
162
180
  }
181
+
163
182
  .data-table-heading {
164
183
  display: none;
165
184
  }
@@ -181,10 +200,11 @@
181
200
  margin-bottom: 1.5rem;
182
201
 
183
202
  // Remove padding from first and last columns to keep content flush to edges
184
- > [class*='col-']:first-child {
203
+ >[class*='col-']:first-child {
185
204
  padding-left: 0;
186
205
  }
187
- > [class*='col-']:last-child {
206
+
207
+ >[class*='col-']:last-child {
188
208
  padding-right: 0;
189
209
  }
190
210
 
@@ -199,7 +219,7 @@
199
219
  .row {
200
220
  margin-bottom: 1.5rem;
201
221
 
202
- > [class*='col-'] {
222
+ >[class*='col-'] {
203
223
  // Remove side padding when columns stack to full width
204
224
  padding-left: 0;
205
225
  padding-right: 0;
@@ -207,7 +227,7 @@
207
227
  }
208
228
 
209
229
  // Last column doesn't need margin (row margin handles gap to next row)
210
- > [class*='col-']:last-child {
230
+ >[class*='col-']:last-child {
211
231
  margin-bottom: 0;
212
232
  }
213
233
 
@@ -221,6 +241,7 @@
221
241
  .dashboard-row {
222
242
  display: flex;
223
243
  flex-direction: column;
244
+
224
245
  &.toggle {
225
246
  display: block;
226
247
  }
@@ -228,9 +249,10 @@
228
249
 
229
250
  .dashboard-col {
230
251
  margin: 0;
252
+
231
253
  // Disable the module individual margin
232
254
  .map-container,
233
- .cdc-chart-inner-container > * {
255
+ .cove-visualization.type-chart .cove-visualization__body>* {
234
256
  margin-left: 0;
235
257
  margin-right: 0;
236
258
  }
@@ -261,6 +283,7 @@
261
283
  .dashboard-col-8 {
262
284
  width: 66%;
263
285
  }
286
+
264
287
  .dashboard-col-6 {
265
288
  width: 50%;
266
289
  }
@@ -292,42 +315,148 @@
292
315
  padding: 1rem;
293
316
  }
294
317
 
295
- // Ensure Bootstrap rows with data bites stretch columns to equal height
296
- .row:has([class*='bite__style']) {
318
+ // User-configured equal height rows
319
+ .row.equal-height {
297
320
  display: flex !important;
298
321
  align-items: stretch !important;
299
322
 
300
- // Ensure Bootstrap columns are flex containers
301
323
  [class*='col-'] {
302
- display: flex !important;
324
+ display: flex;
303
325
  flex-direction: column !important;
326
+ flex: 1 1 auto !important;
327
+ align-items: stretch !important;
328
+ min-height: 0 !important;
304
329
 
305
- > * {
330
+ >* {
306
331
  display: flex !important;
307
332
  flex-direction: column !important;
308
- flex: 1 !important;
309
- min-height: 0;
310
- width: 100%;
333
+ flex: 1 1 auto !important;
334
+ align-items: stretch !important;
335
+ min-height: 0 !important;
336
+ width: 100% !important;
311
337
  }
312
- }
313
- }
314
338
 
315
- // Ensure Bootstrap rows with TP5 waffle charts stretch columns to equal height
316
- .row:has(.waffle__style--tp5) {
317
- display: flex !important;
318
- align-items: stretch !important;
339
+ .collapsable-multiviz-container,
340
+ .cove-visualization {
341
+ display: flex !important;
342
+ flex-direction: column !important;
343
+ flex: 1 1 auto !important;
344
+ align-items: stretch !important;
345
+ min-height: 0 !important;
346
+ width: 100% !important;
347
+
348
+ >.cove-visualization__content,
349
+ >.cove-visualization__outer,
350
+ >.cove-visualization__inner,
351
+ >.cove-visualization__body {
352
+ display: flex !important;
353
+ flex-direction: column !important;
354
+ flex: 1 1 auto !important;
355
+ align-items: stretch !important;
356
+ min-height: 0 !important;
357
+ width: 100% !important;
358
+
359
+ >.cove-visualization__inner,
360
+ >.cove-visualization__body,
361
+ >.cove-visualization__body-wrap {
362
+ display: flex !important;
363
+ flex-direction: column !important;
364
+ flex: 1 1 auto !important;
365
+ align-items: stretch !important;
366
+ min-height: 0 !important;
367
+ width: 100% !important;
368
+ }
369
+ }
370
+
371
+ .cove-visualization__outer,
372
+ .cove-visualization__inner,
373
+ .cove-visualization__body,
374
+ .cove-visualization__body-wrap {
375
+ display: flex !important;
376
+ flex-direction: column !important;
377
+ flex: 1 1 auto !important;
378
+ align-items: stretch !important;
379
+ min-height: 0 !important;
380
+ width: 100% !important;
381
+ }
382
+ }
319
383
 
320
- // Ensure Bootstrap columns are flex containers
321
- [class*='col-'] {
322
- display: flex !important;
323
- flex-direction: column !important;
384
+ .bite,
385
+ .bite-content-container,
386
+ .bite-content,
387
+ .bite-content__text-wrap,
388
+ .cdc-callout,
389
+ .cdc-callout__content {
390
+ display: flex !important;
391
+ flex-direction: column !important;
392
+ flex: 1 1 auto !important;
393
+ min-height: 0 !important;
394
+ }
324
395
 
325
- > * {
396
+ .cdc-callout__body {
397
+ flex: 1 1 auto !important;
398
+ min-height: 0 !important;
399
+ }
400
+
401
+ .cove-visualization .cove-visualization__body.bite__style--tp5>.cove-visualization__body-wrap {
326
402
  display: flex !important;
327
403
  flex-direction: column !important;
328
- flex: 1 !important;
329
- min-height: 0;
330
- width: 100%;
404
+ flex: 1 1 auto !important;
405
+ min-height: 0 !important;
406
+ }
407
+
408
+ .cove-visualization .cove-visualization__body.bite__style--tp5>.cove-visualization__body-wrap>.cove-visualization__content-section {
409
+ display: flex !important;
410
+ flex-direction: column !important;
411
+ flex: 1 1 auto !important;
412
+ min-height: 0 !important;
413
+ width: 100% !important;
414
+ }
415
+
416
+ .cove-visualization .cove-visualization__body.bite__style--tp5>.cove-visualization__body-wrap>.cove-visualization__content-section>.cdc-callout {
417
+ display: flex !important;
418
+ flex-direction: column !important;
419
+ flex: 1 1 auto !important;
420
+ min-height: 100% !important;
421
+ width: 100% !important;
422
+ }
423
+
424
+ .cove-visualization.waffle__style--tp5 .cove-visualization__body>.cove-visualization__body-wrap,
425
+ .cove-visualization.gauge__style--tp5 .cove-visualization__body>.cove-visualization__body-wrap {
426
+ display: flex !important;
427
+ flex-direction: column !important;
428
+ flex: 1 1 auto !important;
429
+ min-height: 0 !important;
430
+ }
431
+
432
+ .cove-visualization.waffle__style--tp5 .cove-visualization__body>.cove-visualization__body-wrap>.cove-visualization__content-section,
433
+ .cove-visualization.gauge__style--tp5 .cove-visualization__body>.cove-visualization__body-wrap>.cove-visualization__content-section {
434
+ display: flex !important;
435
+ flex-direction: column !important;
436
+ flex: 1 1 auto !important;
437
+ min-height: 0 !important;
438
+ width: 100% !important;
439
+ }
440
+
441
+ .cove-visualization.waffle__style--tp5 .cove-visualization__body>.cove-visualization__body-wrap>.cove-visualization__content-section>.cdc-callout,
442
+ .cove-visualization.gauge__style--tp5 .cove-visualization__body>.cove-visualization__body-wrap>.cove-visualization__content-section>.cdc-callout {
443
+ display: flex !important;
444
+ flex-direction: column !important;
445
+ flex: 1 1 auto !important;
446
+ min-height: 100% !important;
447
+ width: 100% !important;
448
+ }
449
+
450
+ .cove-visualization .cove-visualization__body.bite__style--tp5 .cdc-callout__body {
451
+ display: flex !important;
452
+ flex: 1 1 auto !important;
453
+ align-items: stretch !important;
454
+ min-height: 0 !important;
455
+ }
456
+
457
+ .cove-visualization .cove-visualization__body.bite__style--tp5 .cdc-callout__content {
458
+ flex: 1 1 auto !important;
459
+ min-height: 0 !important;
331
460
  }
332
461
  }
333
462
  }
@@ -346,15 +475,12 @@
346
475
  }
347
476
  }
348
477
 
349
- // TP5 Waffle Chart adjustments when there are 2+ in a row
350
- .row:has(.waffle__style--tp5):has([class*='col-'] ~ [class*='col-']) {
351
- .waffle__style--tp5 {
352
- // Enable flex stretching only in dashboard rows
353
- .cove-component__content {
354
- height: 100%;
355
- display: flex;
356
- flex-direction: column;
357
- }
478
+ // TP5 Waffle/Gauge adjustments when there are 2+ in a row
479
+ .row:has(.waffle__style--tp5):has([class*='col-'] ~ [class*='col-']),
480
+ .row:has(.gauge__style--tp5):has([class*='col-'] ~ [class*='col-']) {
481
+
482
+ .waffle__style--tp5,
483
+ .gauge__style--tp5 {
358
484
 
359
485
  .cdc-callout {
360
486
  flex: 1;
@@ -390,6 +516,7 @@
390
516
 
391
517
  .sub-editor {
392
518
  margin-top: 40px;
519
+
393
520
  .sub-editor-heading {
394
521
  display: flex;
395
522
  align-items: center;
@@ -401,6 +528,7 @@
401
528
  background-color: red;
402
529
  z-index: 101;
403
530
  }
531
+
404
532
  .editor-panel {
405
533
  top: 40px;
406
534
  }
@@ -414,4 +542,4 @@
414
542
  display: block;
415
543
  margin: 1em 0;
416
544
  }
417
- }
545
+ }
@@ -237,7 +237,7 @@ const reducer = (state: DashboardState, action: DashboardActions): DashboardStat
237
237
 
238
238
  const filteredRows = _.map(newRows, row => ({
239
239
  ...row,
240
- columns: _.filter(row.columns, column => column.widget !== uid)
240
+ columns: row.columns.map(column => (column.widget === uid ? _.omit(column, 'widget') : column))
241
241
  }))
242
242
 
243
243
  return {
@@ -1,11 +1,11 @@
1
- import path from 'path'
1
+ import path from 'node:path'
2
2
  import { testStandaloneBuild } from '@cdc/core/helpers/tests/testStandaloneBuild.ts'
3
3
  import { describe, it, expect } from 'vitest'
4
4
 
5
5
  describe('Dashboard', () => {
6
6
  it('Can be built in isolation', async () => {
7
7
  const pkgDir = path.join(__dirname, '..')
8
- const result = testStandaloneBuild(pkgDir)
8
+ const result = await testStandaloneBuild(pkgDir)
9
9
  expect(result).toBe(true)
10
10
  }, 300000)
11
11
  })
@@ -0,0 +1,74 @@
1
+ import React from 'react'
2
+ import { render } from '@testing-library/react'
3
+ import { describe, expect, it } from 'vitest'
4
+ import CdcDashboardComponent from '../CdcDashboardComponent'
5
+ import type { InitialState } from '../types/InitialState'
6
+
7
+ describe('CdcDashboardComponent', () => {
8
+ it('renders dashboard markup through the shared visualization shell', () => {
9
+ const initialState = {
10
+ config: {
11
+ type: 'dashboard',
12
+ dashboard: {
13
+ title: 'Dashboard Title',
14
+ titleStyle: 'small',
15
+ theme: 'theme-blue',
16
+ sharedFilters: []
17
+ },
18
+ visualizations: {},
19
+ rows: [],
20
+ datasets: {},
21
+ table: {}
22
+ },
23
+ data: {},
24
+ loading: false,
25
+ filteredData: {},
26
+ preview: false,
27
+ tabSelected: 'Dashboard Preview',
28
+ filtersApplied: true
29
+ } as InitialState
30
+
31
+ const { container } = render(
32
+ <CdcDashboardComponent initialState={initialState} interactionLabel='dashboard-test' isEditor={false} />
33
+ )
34
+
35
+ const shell = container.querySelector('.cove-visualization')
36
+
37
+ expect(shell).toHaveClass('type-dashboard')
38
+ expect(shell).toHaveAttribute('data-download-id')
39
+ expect(shell?.querySelector('.cove-visualization__outer')).toBeInTheDocument()
40
+ })
41
+
42
+ it('keeps the dashboard root out of the shared editor grid layout', () => {
43
+ const initialState = {
44
+ config: {
45
+ type: 'dashboard',
46
+ dashboard: {
47
+ title: 'Dashboard Title',
48
+ titleStyle: 'small',
49
+ theme: 'theme-blue',
50
+ sharedFilters: []
51
+ },
52
+ visualizations: {},
53
+ rows: [],
54
+ datasets: {},
55
+ table: {}
56
+ },
57
+ data: {},
58
+ loading: false,
59
+ filteredData: {},
60
+ preview: false,
61
+ tabSelected: 'Dashboard Preview',
62
+ filtersApplied: true
63
+ } as InitialState
64
+
65
+ const { container } = render(
66
+ <CdcDashboardComponent initialState={initialState} interactionLabel='dashboard-test' isEditor={true} />
67
+ )
68
+
69
+ const shell = container.querySelector('.cove-visualization')
70
+
71
+ expect(shell).toHaveClass('type-dashboard', 'is-dashboard-editor')
72
+ expect(shell).not.toHaveClass('is-editor')
73
+ })
74
+ })
@@ -2,7 +2,8 @@ export const FILTER_STYLE = {
2
2
  combobox: 'combobox',
3
3
  dropdown: 'dropdown',
4
4
  multiSelect: 'multi-select',
5
- nestedDropdown: 'nested-dropdown'
5
+ nestedDropdown: 'nested-dropdown',
6
+ tabSimple: 'tab-simple'
6
7
  } as const
7
8
 
8
9
  export type FilterStyle = (typeof FILTER_STYLE)[keyof typeof FILTER_STYLE]
@@ -0,0 +1,89 @@
1
+ {
2
+ "dashboard": {
3
+ "theme": "theme-blue",
4
+ "title": "Metadata Test Dashboard",
5
+ "sharedFilters": [
6
+ {
7
+ "values": ["Alabama", "Alaska"],
8
+ "columnName": "Location",
9
+ "showDropdown": true,
10
+ "usedBy": ["chart-metadata-test", "databite-metadata-test"],
11
+ "tier": 1,
12
+ "type": "datafilter"
13
+ }
14
+ ]
15
+ },
16
+ "rows": [
17
+ {
18
+ "columns": [
19
+ { "width": 12, "widget": "legacySharedFilters" }
20
+ ]
21
+ },
22
+ {
23
+ "columns": [
24
+ { "width": 6, "widget": "chart-metadata-test" },
25
+ { "width": 6, "widget": "databite-metadata-test" }
26
+ ]
27
+ }
28
+ ],
29
+ "visualizations": {
30
+ "chart-metadata-test": {
31
+ "type": "chart",
32
+ "visualizationType": "Bar",
33
+ "uid": "chart-metadata-test",
34
+ "title": "Amount by Year",
35
+ "description": "Data last updated {{lastUpdated}}",
36
+ "enableMarkupVariables": true,
37
+ "markupVariables": [
38
+ {
39
+ "name": "Last Updated",
40
+ "tag": "{{lastUpdated}}",
41
+ "metadataKey": "lastUpdated",
42
+ "conditions": []
43
+ }
44
+ ],
45
+ "xAxis": { "dataKey": "Year" },
46
+ "series": [{ "dataKey": "Amount", "type": "Bar" }],
47
+ "dataKey": "metadata-test-data",
48
+ "theme": "theme-blue"
49
+ },
50
+ "databite-metadata-test": {
51
+ "type": "data-bite",
52
+ "visualizationType": "data-bite",
53
+ "uid": "databite-metadata-test",
54
+ "title": "",
55
+ "subtext": "Source: {{source}}",
56
+ "enableMarkupVariables": true,
57
+ "markupVariables": [
58
+ {
59
+ "name": "Source",
60
+ "tag": "{{source}}",
61
+ "metadataKey": "source",
62
+ "conditions": []
63
+ }
64
+ ],
65
+ "dataColumn": "Amount",
66
+ "dataFunction": "Sum",
67
+ "biteStyle": "title",
68
+ "bitePosition": "Left",
69
+ "biteFontSize": 24,
70
+ "fontSize": "medium",
71
+ "dataFormat": { "roundToPlace": 0, "commas": true },
72
+ "dataKey": "metadata-test-data",
73
+ "theme": "theme-orange"
74
+ },
75
+ "legacySharedFilters": {
76
+ "type": "dashboardFilters",
77
+ "visualizationType": "dashboardFilters",
78
+ "sharedFilterIndexes": [0],
79
+ "filterBehavior": "Filter Change",
80
+ "uid": "legacySharedFilters"
81
+ }
82
+ },
83
+ "table": { "label": "Data Table", "show": false },
84
+ "data": [],
85
+ "dataFileName": "metadata-test-data",
86
+ "dataFileSourceType": "",
87
+ "dataUrl": "/packages/dashboard/examples/data/data-with-metadata.json",
88
+ "type": "dashboard"
89
+ }
package/vite.config.js CHANGED
@@ -1,4 +1,10 @@
1
1
  import GenerateViteConfig from '@cdc/core/generateViteConfig.js'
2
2
  import { moduleName } from './package.json'
3
3
 
4
- export default GenerateViteConfig(moduleName)
4
+ // Dashboard uses is-dashboard-editor instead of is-editor for the padding selector
5
+ const dashboardCss = `
6
+ .cove-visualization.type-dashboard:not(.is-dashboard-editor) {
7
+ padding: 1rem;
8
+ }`
9
+
10
+ export default GenerateViteConfig(moduleName, {}, {}, { css: dashboardCss })