@cdc/dashboard 4.26.2 → 4.26.4

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 (109) hide show
  1. package/CONFIG.md +172 -0
  2. package/README.md +60 -20
  3. package/dist/cdcdashboard-CY9IcPSi.es.js +6 -0
  4. package/dist/cdcdashboard-DlpiY3fQ.es.js +4 -0
  5. package/dist/cdcdashboard.js +56686 -50281
  6. package/examples/__data__/data-2.json +6 -0
  7. package/examples/__data__/data-with-metadata.json +18 -0
  8. package/examples/__data__/data.json +6 -0
  9. package/examples/default.json +7 -36
  10. package/examples/legend-issue.json +1 -1
  11. package/examples/minimal-example.json +34 -0
  12. package/examples/private/dengue.json +4640 -0
  13. package/examples/private/inline-markup.json +775 -0
  14. package/examples/private/link_to_file.json +16662 -0
  15. package/examples/private/recent-update.json +1456 -0
  16. package/examples/private/toggle.json +10137 -0
  17. package/examples/sankey.json +3 -3
  18. package/examples/test-api-filter-reset.json +4 -4
  19. package/examples/tp5-test.json +86 -4
  20. package/package.json +9 -9
  21. package/src/CdcDashboard.tsx +2 -1
  22. package/src/CdcDashboardComponent.tsx +48 -28
  23. package/src/_stories/Dashboard.DataSetup.stories.tsx +6 -1
  24. package/src/_stories/Dashboard.Pages.smoke.stories.tsx +22 -0
  25. package/src/_stories/Dashboard.smoke.stories.tsx +33 -0
  26. package/src/_stories/Dashboard.stories.tsx +4523 -83
  27. package/src/_stories/_mock/dashboard-data-driven-colors.json +171 -0
  28. package/src/_stories/_mock/tab-simple-filter.json +153 -0
  29. package/src/_stories/_mock/tp5-test.json +86 -5
  30. package/src/components/DashboardEditors.tsx +15 -0
  31. package/src/components/DashboardFilters/DashboardFilters.test.tsx +129 -0
  32. package/src/components/DashboardFilters/DashboardFilters.tsx +29 -10
  33. package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +12 -8
  34. package/src/components/DashboardFilters/DashboardFiltersEditor/components/APIModal.tsx +6 -4
  35. package/src/components/DashboardFilters/DashboardFiltersEditor/components/DeleteFilterModal.tsx +59 -58
  36. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.test.tsx +127 -0
  37. package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +29 -6
  38. package/src/components/DashboardFilters/DashboardFiltersEditor/components/NestedDropDownDashboard.tsx +10 -9
  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/ExpandCollapseButtons.tsx +6 -4
  44. package/src/components/Grid.tsx +4 -3
  45. package/src/components/Header/Header.tsx +27 -5
  46. package/src/components/Header/index.scss +1 -1
  47. package/src/components/MultiConfigTabs/MultiConfigTabs.tsx +141 -140
  48. package/src/components/MultiConfigTabs/multiconfigtabs.styles.css +6 -6
  49. package/src/components/Row.tsx +30 -8
  50. package/src/components/Toggle/toggle-style.css +7 -7
  51. package/src/components/VisualizationRow.tsx +81 -22
  52. package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +2 -55
  53. package/src/components/VisualizationsPanel/visualizations-panel-styles.css +2 -2
  54. package/src/components/Widget/Widget.tsx +7 -6
  55. package/src/components/Widget/widget.styles.css +48 -17
  56. package/src/data/initial-state.js +2 -1
  57. package/src/helpers/addVisualization.ts +73 -0
  58. package/src/helpers/formatConfigBeforeSave.ts +1 -1
  59. package/src/helpers/getVizConfig.ts +13 -3
  60. package/src/helpers/iconHash.tsx +45 -36
  61. package/src/helpers/processDataLegacy.ts +19 -14
  62. package/src/helpers/tests/addVisualization.test.ts +52 -0
  63. package/src/helpers/tests/formatConfigBeforeSave.test.ts +81 -1
  64. package/src/scss/editor-panel.scss +1 -1
  65. package/src/scss/grid.scss +38 -8
  66. package/src/scss/main.scss +237 -40
  67. package/src/store/dashboard.reducer.ts +2 -1
  68. package/src/test/CdcDashboard.test.jsx +26 -2
  69. package/src/test/CdcDashboardComponent.test.tsx +74 -0
  70. package/src/types/FilterStyles.ts +2 -1
  71. package/src/types/SharedFilter.ts +1 -0
  72. package/tests/fixtures/dashboard-config-with-metadata.json +89 -0
  73. package/vite.config.js +2 -2
  74. package/dist/cdcdashboard-Cf9_fbQf.es.js +0 -6
  75. package/examples/DEV-6574.json +0 -2224
  76. package/examples/api-dashboard-data.json +0 -272
  77. package/examples/api-dashboard-years.json +0 -11
  78. package/examples/api-geographies-data.json +0 -11
  79. package/examples/chart-data.json +0 -5409
  80. package/examples/custom/css/respiratory.css +0 -236
  81. package/examples/custom/js/respiratory.js +0 -242
  82. package/examples/default-data.json +0 -368
  83. package/examples/default-filter-control.json +0 -209
  84. package/examples/default-multi-dataset-shared-filter.json +0 -1729
  85. package/examples/default-multi-dataset.json +0 -506
  86. package/examples/ed-visits-county-file.json +0 -402
  87. package/examples/filters/Alabama.json +0 -72
  88. package/examples/filters/Alaska.json +0 -1737
  89. package/examples/filters/Arkansas.json +0 -4713
  90. package/examples/filters/California.json +0 -212
  91. package/examples/filters/Colorado.json +0 -1500
  92. package/examples/filters/Connecticut.json +0 -559
  93. package/examples/filters/Delaware.json +0 -63
  94. package/examples/filters/DistrictofColumbia.json +0 -63
  95. package/examples/filters/Florida.json +0 -4217
  96. package/examples/filters/States.json +0 -146
  97. package/examples/state-level.json +0 -90136
  98. package/examples/state-points.json +0 -10474
  99. package/examples/temp-example-data.json +0 -130
  100. package/examples/test-dashboard-simple.json +0 -503
  101. package/examples/test-example.json +0 -752
  102. package/examples/test-file.json +0 -147
  103. package/examples/test.json +0 -752
  104. package/examples/testing.json +0 -94456
  105. /package/examples/{legend-issue-data.json → __data__/legend-issue-data.json} +0 -0
  106. /package/examples/api-test/{categories.json → __data__/categories.json} +0 -0
  107. /package/examples/api-test/{chart-data.json → __data__/chart-data.json} +0 -0
  108. /package/examples/api-test/{topics.json → __data__/topics.json} +0 -0
  109. /package/examples/api-test/{years.json → __data__/years.json} +0 -0
@@ -1,8 +1,13 @@
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';
10
+
6
11
  .loading > div.la-ball-beat {
7
12
  margin-top: 20%;
8
13
  }
@@ -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);
@@ -121,12 +135,15 @@
121
135
  }
122
136
  }
123
137
 
124
- .btn {
125
- // Expand and Collapse Buttons for Multiviz Dashboard
126
- &.expand-collapse-buttons {
127
- background-color: var(--lightestGray);
128
- border: 1px var(--lightGray) solid;
129
- color: black;
138
+ .dashboard-filters__actions {
139
+ align-items: flex-end;
140
+ display: flex;
141
+ flex: 0 0 auto;
142
+ width: auto;
143
+
144
+ > .cove-button {
145
+ flex: 0 0 auto;
146
+ width: auto;
130
147
  }
131
148
  }
132
149
 
@@ -139,11 +156,13 @@
139
156
  border: var(--lightGray) 1px solid;
140
157
  clear: both;
141
158
  margin-bottom: 20px;
159
+
142
160
  .multi-visualiation-heading {
143
161
  position: relative;
144
162
  background: var(--lightestGray);
145
163
  padding: 0.5em 0.7em;
146
164
  cursor: pointer;
165
+
147
166
  svg {
148
167
  position: absolute;
149
168
  height: 100%;
@@ -156,10 +175,12 @@
156
175
  z-index: 2;
157
176
  position: relative;
158
177
  }
178
+
159
179
  @include breakpoint(xs) {
160
180
  font-size: 0.9em;
161
181
  }
162
182
  }
183
+
163
184
  .data-table-heading {
164
185
  display: none;
165
186
  }
@@ -184,6 +205,7 @@
184
205
  > [class*='col-']:first-child {
185
206
  padding-left: 0;
186
207
  }
208
+
187
209
  > [class*='col-']:last-child {
188
210
  padding-right: 0;
189
211
  }
@@ -221,6 +243,7 @@
221
243
  .dashboard-row {
222
244
  display: flex;
223
245
  flex-direction: column;
246
+
224
247
  &.toggle {
225
248
  display: block;
226
249
  }
@@ -228,9 +251,10 @@
228
251
 
229
252
  .dashboard-col {
230
253
  margin: 0;
254
+
231
255
  // Disable the module individual margin
232
256
  .map-container,
233
- .cdc-chart-inner-container > * {
257
+ .cove-visualization.type-chart .cove-visualization__body > * {
234
258
  margin-left: 0;
235
259
  margin-right: 0;
236
260
  }
@@ -261,6 +285,7 @@
261
285
  .dashboard-col-8 {
262
286
  width: 66%;
263
287
  }
288
+
264
289
  .dashboard-col-6 {
265
290
  width: 50%;
266
291
  }
@@ -292,43 +317,212 @@
292
317
  padding: 1rem;
293
318
  }
294
319
 
295
- // Ensure Bootstrap rows with data bites stretch columns to equal height
296
- .row:has([class*='bite__style']) {
320
+ // User-configured equal height rows
321
+ .row.equal-height {
297
322
  display: flex !important;
298
323
  align-items: stretch !important;
299
324
 
300
- // Ensure Bootstrap columns are flex containers
301
325
  [class*='col-'] {
302
- display: flex !important;
326
+ display: flex;
303
327
  flex-direction: column !important;
328
+ flex: 1 1 auto !important;
329
+ align-items: stretch !important;
330
+ min-height: 0 !important;
304
331
 
305
332
  > * {
306
333
  display: flex !important;
307
334
  flex-direction: column !important;
308
- flex: 1 !important;
309
- min-height: 0;
310
- width: 100%;
335
+ flex: 1 1 auto !important;
336
+ align-items: stretch !important;
337
+ min-height: 0 !important;
338
+ width: 100% !important;
311
339
  }
312
- }
313
- }
314
340
 
315
- // Ensure Bootstrap rows with TP5 waffle/gauge charts stretch columns to equal height
316
- .row:has(.waffle__style--tp5),
317
- .row:has(.gauge__style--tp5) {
318
- display: flex !important;
319
- align-items: stretch !important;
341
+ .collapsable-multiviz-container,
342
+ .cove-visualization {
343
+ display: flex !important;
344
+ flex-direction: column !important;
345
+ flex: 1 1 auto !important;
346
+ align-items: stretch !important;
347
+ min-height: 0 !important;
348
+ width: 100% !important;
349
+
350
+ > .cove-visualization__content,
351
+ > .cove-visualization__outer,
352
+ > .cove-visualization__inner,
353
+ > .cove-visualization__body {
354
+ display: flex !important;
355
+ flex-direction: column !important;
356
+ flex: 1 1 auto !important;
357
+ align-items: stretch !important;
358
+ min-height: 0 !important;
359
+ width: 100% !important;
360
+
361
+ > .cove-visualization__inner,
362
+ > .cove-visualization__body,
363
+ > .cove-visualization__body-wrap {
364
+ display: flex !important;
365
+ flex-direction: column !important;
366
+ flex: 1 1 auto !important;
367
+ align-items: stretch !important;
368
+ min-height: 0 !important;
369
+ width: 100% !important;
370
+ }
371
+ }
372
+
373
+ .cove-visualization__outer,
374
+ .cove-visualization__inner,
375
+ .cove-visualization__body,
376
+ .cove-visualization__body-wrap,
377
+ .markup-include-tp5 {
378
+ display: flex !important;
379
+ flex-direction: column !important;
380
+ flex: 1 1 auto !important;
381
+ align-items: stretch !important;
382
+ min-height: 0 !important;
383
+ width: 100% !important;
384
+ }
385
+ }
320
386
 
321
- // Ensure Bootstrap columns are flex containers
322
- [class*='col-'] {
323
- display: flex !important;
324
- flex-direction: column !important;
387
+ .bite,
388
+ .bite-content-container,
389
+ .bite-content,
390
+ .bite-content__text-wrap,
391
+ .cdc-callout,
392
+ .cdc-callout__content {
393
+ display: flex !important;
394
+ flex-direction: column !important;
395
+ flex: 1 1 auto !important;
396
+ min-height: 0 !important;
397
+ }
325
398
 
326
- > * {
399
+ .cdc-callout__body {
400
+ flex: 1 1 auto !important;
401
+ min-height: 0 !important;
402
+ }
403
+
404
+ .cove-visualization .cove-visualization__body.bite__style--tp5 > .cove-visualization__body-wrap {
327
405
  display: flex !important;
328
406
  flex-direction: column !important;
329
- flex: 1 !important;
330
- min-height: 0;
331
- width: 100%;
407
+ flex: 1 1 auto !important;
408
+ min-height: 0 !important;
409
+ }
410
+
411
+ .cove-visualization
412
+ .cove-visualization__body.bite__style--tp5
413
+ > .cove-visualization__body-wrap
414
+ > .cove-visualization__content-section {
415
+ display: flex !important;
416
+ flex-direction: column !important;
417
+ flex: 1 1 auto !important;
418
+ min-height: 0 !important;
419
+ width: 100% !important;
420
+ }
421
+
422
+ .cove-visualization
423
+ .cove-visualization__body.bite__style--tp5
424
+ > .cove-visualization__body-wrap
425
+ > .cove-visualization__content-section
426
+ > .cdc-callout {
427
+ display: flex !important;
428
+ flex-direction: column !important;
429
+ flex: 1 1 auto !important;
430
+ min-height: 100% !important;
431
+ width: 100% !important;
432
+ }
433
+
434
+ .cove-visualization.waffle__style--tp5 .cove-visualization__body > .cove-visualization__body-wrap,
435
+ .cove-visualization.gauge__style--tp5 .cove-visualization__body > .cove-visualization__body-wrap,
436
+ .cove-visualization.markup-include__style--tp5 .cove-visualization__body > .cove-visualization__body-wrap {
437
+ display: flex !important;
438
+ flex-direction: column !important;
439
+ flex: 1 1 auto !important;
440
+ min-height: 0 !important;
441
+ }
442
+
443
+ .cove-visualization.waffle__style--tp5
444
+ .cove-visualization__body
445
+ > .cove-visualization__body-wrap
446
+ > .cove-visualization__content-section,
447
+ .cove-visualization.gauge__style--tp5
448
+ .cove-visualization__body
449
+ > .cove-visualization__body-wrap
450
+ > .cove-visualization__content-section,
451
+ .cove-visualization.markup-include__style--tp5
452
+ .cove-visualization__body
453
+ > .cove-visualization__body-wrap
454
+ > .cove-visualization__content-section {
455
+ display: flex !important;
456
+ flex-direction: column !important;
457
+ flex: 1 1 auto !important;
458
+ min-height: 0 !important;
459
+ width: 100% !important;
460
+ }
461
+
462
+ .cove-visualization.waffle__style--tp5
463
+ .cove-visualization__body
464
+ > .cove-visualization__body-wrap
465
+ > .cove-visualization__content-section
466
+ > .cdc-callout,
467
+ .cove-visualization.gauge__style--tp5
468
+ .cove-visualization__body
469
+ > .cove-visualization__body-wrap
470
+ > .cove-visualization__content-section
471
+ > .cdc-callout {
472
+ display: flex !important;
473
+ flex-direction: column !important;
474
+ flex: 1 1 auto !important;
475
+ min-height: 100% !important;
476
+ width: 100% !important;
477
+ }
478
+
479
+ .cove-visualization.markup-include__style--tp5
480
+ .cove-visualization__body
481
+ > .cove-visualization__body-wrap
482
+ > .cove-visualization__content-section
483
+ > .markup-include-tp5 {
484
+ display: flex !important;
485
+ flex-direction: column !important;
486
+ flex: 1 1 auto !important;
487
+ min-height: 100% !important;
488
+ width: 100% !important;
489
+ }
490
+
491
+ .cove-visualization.markup-include__style--tp5
492
+ .cove-visualization__body
493
+ > .cove-visualization__body-wrap
494
+ > .cove-visualization__content-section
495
+ > .markup-include-tp5
496
+ > .cdc-callout__body,
497
+ .cove-visualization.markup-include__style--tp5
498
+ .cove-visualization__body
499
+ > .cove-visualization__body-wrap
500
+ > .cove-visualization__content-section
501
+ > .markup-include-tp5
502
+ > .cdc-callout__body
503
+ > .cdc-callout__content {
504
+ display: flex !important;
505
+ flex: 1 1 auto !important;
506
+ min-height: 0 !important;
507
+ }
508
+
509
+ .cove-visualization.markup-include__style--tp5 .markup-include-component--tp5 {
510
+ display: flex !important;
511
+ flex-direction: column !important;
512
+ flex: 1 1 auto !important;
513
+ min-height: 0 !important;
514
+ }
515
+
516
+ .cove-visualization .cove-visualization__body.bite__style--tp5 .cdc-callout__body {
517
+ display: grid !important;
518
+ flex: 1 1 auto !important;
519
+ align-items: start !important;
520
+ min-height: 0 !important;
521
+ }
522
+
523
+ .cove-visualization .cove-visualization__body.bite__style--tp5 .cdc-callout__content {
524
+ flex: 1 1 auto !important;
525
+ min-height: 0 !important;
332
526
  }
333
527
  }
334
528
  }
@@ -352,13 +546,6 @@
352
546
  .row:has(.gauge__style--tp5):has([class*='col-'] ~ [class*='col-']) {
353
547
  .waffle__style--tp5,
354
548
  .gauge__style--tp5 {
355
- // Enable flex stretching only in dashboard rows
356
- .cove-component__content {
357
- height: 100%;
358
- display: flex;
359
- flex-direction: column;
360
- }
361
-
362
549
  .cdc-callout {
363
550
  flex: 1;
364
551
  }
@@ -374,8 +561,6 @@
374
561
  }
375
562
 
376
563
  .cdc-callout__heading {
377
- // Fixed minimum height to align titles - adjust based on design needs
378
- min-height: 3em;
379
564
  display: flex;
380
565
  align-items: flex-start;
381
566
  }
@@ -387,12 +572,23 @@
387
572
  }
388
573
  }
389
574
 
575
+ // TP5 Markup Include adjustments when there are 2+ in a row
576
+ .row:has(.markup-include__style--tp5):has([class*='col-'] ~ [class*='col-']) {
577
+ .markup-include__style--tp5 {
578
+ .cdc-callout__heading {
579
+ display: flex;
580
+ align-items: flex-start;
581
+ }
582
+ }
583
+ }
584
+
390
585
  // Data bite alignment styles are now in packages/data-bite/src/scss/bite.scss
391
586
  // under .cdc-dashboard-inner-container to ensure proper specificity
392
587
  }
393
588
 
394
589
  .sub-editor {
395
590
  margin-top: 40px;
591
+
396
592
  .sub-editor-heading {
397
593
  display: flex;
398
594
  align-items: center;
@@ -404,6 +600,7 @@
404
600
  background-color: red;
405
601
  z-index: 101;
406
602
  }
603
+
407
604
  .editor-panel {
408
605
  top: 40px;
409
606
  }
@@ -24,6 +24,7 @@ const createBlankDashboard: () => BlankMultiConfig = () => ({
24
24
  label: 'Data Table',
25
25
  show: false,
26
26
  showDownloadUrl: false,
27
+ downloadUrlLabel: '',
27
28
  showVertical: true
28
29
  }
29
30
  })
@@ -237,7 +238,7 @@ const reducer = (state: DashboardState, action: DashboardActions): DashboardStat
237
238
 
238
239
  const filteredRows = _.map(newRows, row => ({
239
240
  ...row,
240
- columns: _.filter(row.columns, column => column.widget !== uid)
241
+ columns: row.columns.map(column => (column.widget === uid ? _.omit(column, 'widget') : column))
241
242
  }))
242
243
 
243
244
  return {
@@ -1,11 +1,35 @@
1
- import path from 'path'
1
+ import path from 'node:path'
2
+ import fs from 'node:fs'
3
+ import vm from 'node:vm'
2
4
  import { testStandaloneBuild } from '@cdc/core/helpers/tests/testStandaloneBuild.ts'
3
5
  import { describe, it, expect } from 'vitest'
4
6
 
7
+ const extractMarkedExampleConfig = (content, label) => {
8
+ const match = content.match(
9
+ /<!-- README_EXAMPLE_CONFIG_START -->\s*```jsx\s*([\s\S]*?)\s*```\s*<!-- README_EXAMPLE_CONFIG_END -->/
10
+ )
11
+ expect(match, `${label} should contain a marked README example block`).toBeTruthy()
12
+ const configMatch = match[1].match(/const config = (\{[\s\S]*?\})\n\nfunction App\(\)/)
13
+ expect(configMatch, `${label} should define const config before function App()`).toBeTruthy()
14
+ return vm.runInNewContext(`(${configMatch[1]})`)
15
+ }
16
+
5
17
  describe('Dashboard', () => {
6
18
  it('Can be built in isolation', async () => {
7
19
  const pkgDir = path.join(__dirname, '..')
8
- const result = testStandaloneBuild(pkgDir)
20
+ const result = await testStandaloneBuild(pkgDir)
9
21
  expect(result).toBe(true)
10
22
  }, 300000)
23
+
24
+ it('keeps the minimal example in sync with the README docs', () => {
25
+ const pkgRoot = path.join(__dirname, '..', '..')
26
+ const minimalExamplePath = path.join(pkgRoot, 'examples', 'minimal-example.json')
27
+ const readmePath = path.join(pkgRoot, 'README.md')
28
+
29
+ const minimalExample = JSON.parse(fs.readFileSync(minimalExamplePath, 'utf8'))
30
+ const readmeBlock = extractMarkedExampleConfig(fs.readFileSync(readmePath, 'utf8'), 'README.md')
31
+
32
+ expect(readmeBlock).toEqual(minimalExample)
33
+ expect(minimalExample.version).toBeTruthy()
34
+ })
11
35
  })
@@ -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]
@@ -8,6 +8,7 @@ export type SharedFilter = FilterBase & {
8
8
  filterStyle: FilterStyle
9
9
  queryParameter?: string
10
10
  setByQueryParameter?: string
11
+ displaySubgroupingOnly?: boolean
11
12
  active?: string | string[]
12
13
  queuedActive?: string | string[]
13
14
  usedBy?: (string | number)[] // if number used by whole row, else used by specific viz
@@ -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,9 +1,9 @@
1
1
  import GenerateViteConfig from '@cdc/core/generateViteConfig.js'
2
2
  import { moduleName } from './package.json'
3
3
 
4
- // Dashboard uses isDashboardEditor instead of isEditor for the padding selector
4
+ // Dashboard uses is-dashboard-editor instead of is-editor for the padding selector
5
5
  const dashboardCss = `
6
- .cdc-open-viz-module.type-dashboard:not(.isDashboardEditor) {
6
+ .cove-visualization.type-dashboard:not(.is-dashboard-editor) {
7
7
  padding: 1rem;
8
8
  }`
9
9