@cdc/core 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.
- package/.claude/agents/qa-test-developer.md +126 -0
- package/CLAUDE.local.md +67 -0
- package/LICENSE +201 -0
- package/_stories/Gallery.Charts.stories.tsx +35 -42
- package/_stories/Gallery.DataBite.stories.tsx +15 -8
- package/_stories/Gallery.Maps.stories.tsx +37 -28
- package/_stories/Gallery.WaffleChart.stories.tsx +1 -1
- package/_stories/PageART.stories.tsx +5 -4
- package/_stories/PageBRFSS.stories.tsx +21 -16
- package/_stories/PageCancerRegistries.stories.tsx +15 -15
- package/_stories/PageEasternEquineEncephalitis.stories.tsx +33 -19
- package/_stories/PageExcessiveAlcoholUse.stories.tsx +148 -143
- package/_stories/PageMaternalMortality.stories.tsx +5 -4
- package/_stories/PageOralHealth.stories.tsx +15 -10
- package/_stories/PageRespiratory.stories.tsx +4 -4
- package/_stories/PageSmokingTobacco.stories.tsx +15 -10
- package/_stories/PageStateDiabetesProfiles.stories.tsx +15 -10
- package/_stories/PageWastewater.stories.tsx +44 -30
- package/_stories/VegaImport.stories.tsx +401 -0
- package/_stories/vega-fixtures/bars-with-line.json +444 -0
- package/_stories/vega-fixtures/bars.json +58 -0
- package/_stories/vega-fixtures/combo-bar-rolling-mean.json +88 -0
- package/_stories/vega-fixtures/combo.json +68 -0
- package/_stories/vega-fixtures/grouped-horizontal-bars.json +83 -0
- package/_stories/vega-fixtures/grouped-horizontal-bars2.json +231 -0
- package/_stories/vega-fixtures/horizontal-bar.json +427 -0
- package/_stories/vega-fixtures/horizontal-bars-with-bad-colors.json +197 -0
- package/_stories/vega-fixtures/horizontal-bars2.json +58 -0
- package/_stories/vega-fixtures/lines.json +227 -0
- package/_stories/vega-fixtures/measles-bars.json +348 -0
- package/_stories/vega-fixtures/measles-map.json +11101 -0
- package/_stories/vega-fixtures/measles-stacked-bars.json +2147 -0
- package/_stories/vega-fixtures/multi-dataset.json +255 -0
- package/_stories/vega-fixtures/no-data.json +14 -0
- package/_stories/vega-fixtures/pie-chart.json +94 -0
- package/_stories/vega-fixtures/repeat-spec.json +47 -0
- package/_stories/vega-fixtures/stacked-area.json +222 -0
- package/_stories/vega-fixtures/stacked-bar-with-rect.json +3412 -0
- package/_stories/vega-fixtures/stacked-bars-with-line.json +364 -0
- package/_stories/vega-fixtures/stacked-bars.json +212 -0
- package/_stories/vega-fixtures/stacked-horizontal-bars.json +140 -0
- package/_stories/vega-fixtures/warning-combo.json +59 -0
- package/_stories/vega-fixtures/warning-scatter-and-line.json +1182 -0
- package/assets/callout-flag.svg +7 -0
- package/assets/icon-chart-area.svg +1 -0
- package/assets/icon-chart-radar.svg +23 -0
- package/assets/logo2.svg +31 -0
- package/components/AdvancedEditor/EmbedEditor.tsx +270 -38
- package/components/Alert/components/Alert.styles.css +2 -2
- package/components/ComboBox/combobox.styles.css +48 -48
- package/components/CustomColorsEditor/CustomColorsEditor.css +53 -53
- package/components/CustomColorsEditor/CustomColorsEditor.tsx +3 -10
- package/components/DataTable/DataTable.tsx +46 -18
- package/components/DataTable/DataTableStandAlone.tsx +1 -0
- package/components/DataTable/components/ChartHeader.tsx +21 -12
- package/components/DataTable/components/MapHeader.tsx +34 -28
- package/components/DataTable/components/SortIcon/sort-icon.css +5 -5
- package/components/DataTable/data-table.css +50 -52
- package/components/DataTable/helpers/applyCustomOrder.ts +17 -0
- package/components/DataTable/helpers/getChartCellValue.ts +10 -7
- package/components/DataTable/helpers/getMapDataTableColumnKeys.ts +22 -0
- package/components/DataTable/helpers/getSeriesName.ts +6 -0
- package/components/DataTable/helpers/mapCellMatrix.tsx +33 -23
- package/components/DataTable/helpers/tests/mapCellMatrix.test.ts +33 -0
- package/components/DownloadButton.tsx +14 -6
- package/components/EditorPanel/ColumnsEditor.tsx +38 -31
- package/components/EditorPanel/CustomSortOrder.tsx +94 -0
- package/components/EditorPanel/DataTableEditor.tsx +139 -23
- package/components/EditorPanel/EditorPanel.styles.css +71 -71
- package/components/EditorPanel/EditorPanel.tsx +3 -8
- package/components/EditorPanel/EditorPanelDispatch.tsx +4 -4
- package/components/EditorPanel/FootnotesEditor.tsx +2 -2
- package/components/EditorPanel/VizFilterEditor/NestedDropdownEditor.tsx +21 -12
- package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +16 -10
- package/components/EditorPanel/VizFilterEditor/components/FilterOrder.tsx +33 -29
- package/components/EditorPanel/components/MarkupVariablesEditor.tsx +160 -106
- package/components/EditorPanel/components/PanelMarkup.tsx +5 -1
- package/{styles/v2/components → components/EditorPanel}/editor.scss +76 -22
- package/components/EditorPanel/sections/StyleTreatmentSection.tsx +99 -0
- package/components/EditorPanel/sections/VisualSection.tsx +11 -0
- package/components/EditorWrapper/editor-wrapper.style.css +1 -1
- package/components/Filters/Filters.tsx +3 -5
- package/components/Filters/components/Tabs.tsx +19 -7
- package/{styles → components/Filters}/filters.scss +3 -3
- package/components/Footnotes/FootnotesStandAlone.tsx +4 -2
- package/components/HeaderThemeSelector/HeaderThemeSelector.css +61 -5
- package/components/Layout/components/Responsive.tsx +14 -6
- package/components/Layout/components/Sidebar/components/Sidebar.tsx +1 -1
- package/components/Layout/components/Sidebar/components/sidebar.styles.scss +14 -20
- package/components/Layout/components/Visualization/index.tsx +50 -38
- package/components/Layout/components/Visualization/visualizations.scss +232 -15
- package/components/Layout/components/VisualizationContainer.test.tsx +67 -0
- package/components/Layout/components/VisualizationContainer.tsx +37 -0
- package/components/Layout/components/VisualizationContent.test.tsx +182 -0
- package/components/Layout/components/VisualizationContent.tsx +75 -0
- package/components/Layout/index.tsx +5 -5
- package/components/Layout/styles/editor-utils.scss +3 -3
- package/components/Layout/styles/editor.scss +4 -4
- package/components/Legend/Legend.Gradient.tsx +7 -1
- package/components/Loader/loader.styles.css +2 -2
- package/components/Loading.jsx +1 -1
- package/components/MediaControls.tsx +10 -3
- package/components/MultiSelect/multiselect.styles.css +19 -19
- package/components/NestedDropdown/nesteddropdown.styles.css +15 -15
- package/components/PaletteSelector/PaletteSelector.css +15 -15
- package/components/RichTooltip/richTooltip.css +6 -6
- package/components/Table/table.styles.css +2 -2
- package/components/Waiting.tsx +1 -1
- package/components/_stories/CustomColorsEditor.stories.tsx +37 -0
- package/components/_stories/DataTable.stories.tsx +1 -0
- package/components/_stories/Filters.stories.tsx +1 -1
- package/components/_stories/styles.scss +0 -1
- package/components/elements/Button.jsx +1 -1
- package/components/elements/Card.jsx +1 -1
- package/{styles/v2/components → components/elements}/button.scss +9 -8
- package/components/inputs/InputCheckbox.jsx +1 -1
- package/components/inputs/InputSelect.tsx +1 -1
- package/components/inputs/InputText.jsx +1 -1
- package/components/inputs/InputToggle.tsx +1 -1
- package/{styles/v2/components/input → components/inputs}/_input-check-radio.scss +2 -2
- package/{styles/v2/components/input → components/inputs}/_input-group.scss +3 -3
- package/{styles/v2/components/input → components/inputs}/_input-slider.scss +2 -2
- package/{styles/v2/components/input → components/inputs}/_input.scss +5 -5
- package/{styles/v2/components/input → components/inputs}/index.scss +2 -2
- package/{styles → components}/loading.scss +1 -1
- package/components/managers/DataDesigner.tsx +1 -1
- package/{styles/v2/components → components/managers}/data-designer.scss +6 -7
- package/components/ui/Accordion.jsx +1 -1
- package/components/ui/Icon.tsx +1 -1
- package/components/ui/LoadSpin.jsx +1 -1
- package/components/ui/Modal.jsx +1 -1
- package/components/ui/Overlay.jsx +1 -1
- package/components/ui/Title/index.test.tsx +34 -0
- package/components/ui/Title/index.tsx +24 -7
- package/components/ui/Title/title.styles.css +119 -25
- package/components/ui/Tooltip.tsx +1 -1
- package/components/ui/_stories/Title.stories.tsx +1 -1
- package/{styles/v2/components → components/ui}/accordion.scss +3 -3
- package/components/ui/accordion.styles.css +11 -11
- package/{styles/v2/components → components/ui}/modal.scss +2 -2
- package/{styles/v2/components → components/ui}/overlay.scss +6 -6
- package/{styles/v2/components → components}/ui/tooltip.scss +1 -1
- package/{styles → components}/waiting.scss +9 -3
- package/data/colorPalettes.ts +18 -5
- package/data/mapColorPalettes.ts +10 -0
- package/devTemplate/dev.js +285 -0
- package/devTemplate/index.html +30 -0
- package/devTemplate/preview.html +1503 -0
- package/devTemplate/sidebar.css +151 -0
- package/dist/cove-main.css +2530 -3901
- package/dist/cove-main.css.map +1 -1
- package/generateViteConfig.js +111 -2
- package/helpers/DataTransform.ts +1 -5
- package/helpers/backfillDefaults.ts +35 -0
- package/helpers/constants.ts +12 -0
- package/helpers/cove/date.ts +64 -3
- package/helpers/cove/number.ts +29 -15
- package/helpers/cove/string.ts +29 -0
- package/helpers/coveUpdateWorker.ts +14 -8
- package/helpers/displayDataAsText.ts +1 -1
- package/helpers/embed/embedCodeGenerator.ts +80 -0
- package/helpers/embed/embedHelper.js +169 -0
- package/helpers/embed/filterUtils.ts +121 -0
- package/helpers/embed/index.ts +17 -0
- package/helpers/embed/urlValidation.ts +119 -0
- package/helpers/extractDataAndMetadata.ts +20 -0
- package/helpers/fetchRemoteData.ts +14 -8
- package/helpers/filterVizData.ts +6 -1
- package/helpers/getFileExtension.ts +0 -6
- package/helpers/labelHash.ts +9 -0
- package/helpers/markupProcessor.ts +56 -38
- package/helpers/metrics/types.ts +3 -0
- package/helpers/palettes/colorDistributions.ts +1 -1
- package/helpers/palettes/utils.ts +12 -12
- package/helpers/parseCsvWithQuotes.ts +15 -14
- package/helpers/prepareScreenshot.ts +33 -10
- package/helpers/testing.ts +44 -0
- package/helpers/tests/DataTransform.test.ts +125 -0
- package/helpers/tests/abbreviateNumber.test.ts +59 -0
- package/helpers/tests/backfillDefaults.test.ts +253 -0
- package/helpers/tests/date.test.ts +110 -0
- package/helpers/tests/extractDataAndMetadata.test.ts +93 -0
- package/helpers/tests/markupProcessor.test.ts +315 -124
- package/helpers/tests/number.test.ts +42 -0
- package/helpers/tests/prepareScreenshot.test.ts +28 -28
- package/helpers/tests/testStandaloneBuild.ts +36 -26
- package/helpers/tests/useDataVizClasses.test.ts +66 -0
- package/helpers/tests/visualizationWrapperUsage.test.ts +57 -0
- package/helpers/useDataVizClasses.ts +13 -7
- package/helpers/vegaConfig.ts +1 -1
- package/helpers/vegaConfigImport.ts +160 -0
- package/helpers/ver/4.24.4.ts +24 -0
- package/helpers/ver/4.26.1.ts +1 -1
- package/helpers/ver/4.26.2.ts +84 -0
- package/helpers/ver/4.26.3.ts +44 -0
- package/helpers/ver/4.26.4.ts +31 -0
- package/helpers/ver/tests/4.26.1.test.ts +105 -0
- package/helpers/ver/tests/4.26.2.test.ts +298 -0
- package/helpers/ver/tests/4.26.3.test.ts +168 -0
- package/helpers/ver/tests/4.26.4.test.ts +88 -0
- package/helpers/ver/tests/coveUpdateWorker.test.ts +57 -0
- package/helpers/viewports.ts +2 -0
- package/package.json +27 -32
- package/styles/_global.scss +7 -7
- package/styles/_reset.scss +2 -2
- package/styles/{v2/base → base}/_file-selector.scss +4 -4
- package/styles/{v2/base → base}/_general.scss +2 -4
- package/styles/{v2/base → base}/index.scss +1 -1
- package/styles/base.scss +107 -165
- package/styles/cove-main.scss +3 -6
- package/styles/layout/_component.scss +110 -0
- package/styles/{v2/layout → layout}/_data-table.scss +7 -7
- package/styles/layout/_wrapper-padding.scss +27 -0
- package/styles/{v2/main.scss → main.scss} +3 -1
- package/styles/{v2/themes → themes}/_color-definitions.scss +46 -41
- package/styles/{_accessibility.scss → utils/_accessibility.scss} +1 -1
- package/styles/{v2/utils → utils}/_grid.scss +8 -3
- package/styles/{_global-variables.scss → utils/_properties.scss} +133 -112
- package/styles/{v2/utils → utils}/index.scss +2 -1
- package/types/Annotation.ts +10 -11
- package/types/Axis.ts +2 -0
- package/types/ComponentStyles.ts +1 -0
- package/types/ConfigureData.ts +1 -0
- package/types/General.ts +2 -0
- package/types/MarkupInclude.ts +1 -0
- package/types/MarkupVariable.ts +2 -1
- package/types/Palette.ts +22 -0
- package/types/Table.ts +9 -0
- package/types/Visualization.ts +7 -0
- package/_stories/StoryRenderingTests.stories.tsx +0 -164
- package/helpers/embedCodeGenerator.ts +0 -109
- package/styles/_common-components.css +0 -73
- package/styles/_variables.scss +0 -63
- package/styles/v2/layout/_component.scss +0 -21
- package/styles/v2/utils/_variables.scss +0 -9
- package/{styles/v2/components/card.scss → components/elements/card.css} +2 -2
- /package/{styles/v2/components → components/ui}/icon.scss +0 -0
- /package/{styles/v2/components → components/ui}/loadspin.scss +0 -0
- /package/styles/{v2/base → base}/_heading.scss +0 -0
- /package/styles/{v2/base → base}/_reset.scss +0 -0
- /package/styles/{v2/layout → layout}/_alert.scss +0 -0
- /package/styles/{v2/layout → layout}/_progression.scss +0 -0
- /package/styles/{v2/layout → layout}/_tooltip.scss +0 -0
- /package/styles/{v2/layout → layout}/index.scss +0 -0
- /package/styles/{v2/themes → themes}/index.scss +0 -0
- /package/styles/{v2/utils → utils}/_align.scss +0 -0
- /package/styles/{v2/utils → utils}/_animations.scss +0 -0
- /package/styles/{v2/utils → utils}/_breakpoints.scss +0 -0
- /package/styles/{v2/utils → utils}/_mixins.scss +0 -0
|
@@ -16,7 +16,8 @@ const meta: Meta = {
|
|
|
16
16
|
layout: 'fullscreen',
|
|
17
17
|
docs: {
|
|
18
18
|
description: {
|
|
19
|
-
component:
|
|
19
|
+
component:
|
|
20
|
+
'Stories for visualizations from the CDC Behavioral Risk Factor Surveillance System (BRFSS) Prevalence Data & Data Analysis Tools page (https://www.cdc.gov/brfss/brfssprevalence/index.html)'
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
23
|
},
|
|
@@ -93,12 +94,16 @@ const useConfigWithAbsoluteDataUrl = (configUrl: string) => {
|
|
|
93
94
|
|
|
94
95
|
newDatasets[absoluteKey] = {
|
|
95
96
|
...dataset,
|
|
96
|
-
dataFileName:
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
dataFileName:
|
|
98
|
+
(dataset as any).dataFileName && !(dataset as any).dataFileName.startsWith('http')
|
|
99
|
+
? `https://www.cdc.gov/${(dataset as any).dataFileName
|
|
100
|
+
.replace(/^(\.\.\/)+/, '')
|
|
101
|
+
.replace(/^\//, '')}`
|
|
102
|
+
: (dataset as any).dataFileName,
|
|
103
|
+
dataUrl:
|
|
104
|
+
(dataset as any).dataUrl && !(dataset as any).dataUrl.startsWith('http')
|
|
105
|
+
? `https://www.cdc.gov/${(dataset as any).dataUrl.replace(/^(\.\.\/)+/, '').replace(/^\//, '')}`
|
|
106
|
+
: (dataset as any).dataUrl
|
|
102
107
|
}
|
|
103
108
|
}
|
|
104
109
|
})
|
|
@@ -140,7 +145,7 @@ const testDashboardRendering = async (canvasElement: HTMLElement, storyName: str
|
|
|
140
145
|
const timeout = 30000 // Longer timeout for external data loading
|
|
141
146
|
|
|
142
147
|
const checkDashboard = () => {
|
|
143
|
-
const dashboardElement = canvasElement.querySelector('.
|
|
148
|
+
const dashboardElement = canvasElement.querySelector('.type-dashboard')
|
|
144
149
|
const loadingDiv = canvasElement.querySelector('div')
|
|
145
150
|
|
|
146
151
|
// Log current state for debugging
|
|
@@ -161,12 +166,12 @@ const testDashboardRendering = async (canvasElement: HTMLElement, storyName: str
|
|
|
161
166
|
})
|
|
162
167
|
|
|
163
168
|
await step('Verify dashboard wrapper is present', async () => {
|
|
164
|
-
const dashboard = canvasElement.querySelector('.
|
|
169
|
+
const dashboard = canvasElement.querySelector('.type-dashboard')
|
|
165
170
|
expect(dashboard).toBeInTheDocument()
|
|
166
171
|
})
|
|
167
172
|
|
|
168
173
|
await step('Verify at least one visualization rendered', async () => {
|
|
169
|
-
const coveModules = canvasElement.querySelectorAll('.
|
|
174
|
+
const coveModules = canvasElement.querySelectorAll('.cove-visualization')
|
|
170
175
|
expect(coveModules.length).toBeGreaterThan(0)
|
|
171
176
|
})
|
|
172
177
|
|
|
@@ -224,15 +229,15 @@ export const All_BRFSS_Dashboards: StoryObj = {
|
|
|
224
229
|
}
|
|
225
230
|
|
|
226
231
|
return (
|
|
227
|
-
<div className=
|
|
228
|
-
<h1 className=
|
|
232
|
+
<div className='container-fluid p-4'>
|
|
233
|
+
<h1 className='mb-4'>BRFSS Prevalence Data - All Dashboards</h1>
|
|
229
234
|
|
|
230
|
-
<section className=
|
|
235
|
+
<section className='mb-5'>
|
|
231
236
|
<h2>Explore by Location</h2>
|
|
232
237
|
<Dashboard config={locationConfig} />
|
|
233
238
|
</section>
|
|
234
239
|
|
|
235
|
-
<section className=
|
|
240
|
+
<section className='mb-5'>
|
|
236
241
|
<h2>Explore by Topic</h2>
|
|
237
242
|
<Dashboard config={topicConfig} />
|
|
238
243
|
</section>
|
|
@@ -266,7 +271,7 @@ export const All_BRFSS_Dashboards: StoryObj = {
|
|
|
266
271
|
const timeout = 40000
|
|
267
272
|
|
|
268
273
|
const checkDashboards = () => {
|
|
269
|
-
const dashboards = canvasElement.querySelectorAll('.
|
|
274
|
+
const dashboards = canvasElement.querySelectorAll('.type-dashboard')
|
|
270
275
|
if (dashboards.length >= 2) {
|
|
271
276
|
resolve()
|
|
272
277
|
} else if (Date.now() - startTime > timeout) {
|
|
@@ -280,7 +285,7 @@ export const All_BRFSS_Dashboards: StoryObj = {
|
|
|
280
285
|
})
|
|
281
286
|
|
|
282
287
|
await step('Verify both dashboards are present', async () => {
|
|
283
|
-
const dashboards = canvasElement.querySelectorAll('.
|
|
288
|
+
const dashboards = canvasElement.querySelectorAll('.type-dashboard')
|
|
284
289
|
expect(dashboards.length).toBe(2)
|
|
285
290
|
})
|
|
286
291
|
|
|
@@ -16,7 +16,8 @@ const meta: Meta = {
|
|
|
16
16
|
layout: 'fullscreen',
|
|
17
17
|
docs: {
|
|
18
18
|
description: {
|
|
19
|
-
component:
|
|
19
|
+
component:
|
|
20
|
+
'Stories for visualizations from the CDC National Program of Cancer Registries (NPCR) Contact page (https://www.cdc.gov/national-program-cancer-registries/contact/index.html)'
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
23
|
},
|
|
@@ -92,12 +93,16 @@ const useConfigWithAbsoluteDataUrl = (configUrl: string) => {
|
|
|
92
93
|
|
|
93
94
|
newDatasets[absoluteKey] = {
|
|
94
95
|
...dataset,
|
|
95
|
-
dataFileName:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
dataFileName:
|
|
97
|
+
(dataset as any).dataFileName && !(dataset as any).dataFileName.startsWith('http')
|
|
98
|
+
? `https://www.cdc.gov/${(dataset as any).dataFileName
|
|
99
|
+
.replace(/^(\.\.\/)+/, '')
|
|
100
|
+
.replace(/^\//, '')}`
|
|
101
|
+
: (dataset as any).dataFileName,
|
|
102
|
+
dataUrl:
|
|
103
|
+
(dataset as any).dataUrl && !(dataset as any).dataUrl.startsWith('http')
|
|
104
|
+
? `https://www.cdc.gov/${(dataset as any).dataUrl.replace(/^(\.\.\/)+/, '').replace(/^\//, '')}`
|
|
105
|
+
: (dataset as any).dataUrl
|
|
101
106
|
}
|
|
102
107
|
}
|
|
103
108
|
})
|
|
@@ -139,7 +144,7 @@ const testDashboardRendering = async (canvasElement: HTMLElement, storyName: str
|
|
|
139
144
|
const timeout = 20000
|
|
140
145
|
|
|
141
146
|
const checkDashboard = () => {
|
|
142
|
-
const dashboardElement = canvasElement.querySelector('.
|
|
147
|
+
const dashboardElement = canvasElement.querySelector('.type-dashboard')
|
|
143
148
|
const loadingDiv = canvasElement.querySelector('div')
|
|
144
149
|
|
|
145
150
|
// Log current state for debugging
|
|
@@ -160,20 +165,15 @@ const testDashboardRendering = async (canvasElement: HTMLElement, storyName: str
|
|
|
160
165
|
})
|
|
161
166
|
|
|
162
167
|
await step('Verify dashboard wrapper is present', async () => {
|
|
163
|
-
const dashboard = canvasElement.querySelector('.
|
|
168
|
+
const dashboard = canvasElement.querySelector('.type-dashboard')
|
|
164
169
|
expect(dashboard).toBeInTheDocument()
|
|
165
170
|
})
|
|
166
171
|
|
|
167
172
|
await step('Verify at least one visualization rendered', async () => {
|
|
168
|
-
const coveModules = canvasElement.querySelectorAll('.
|
|
173
|
+
const coveModules = canvasElement.querySelectorAll('.cove-visualization')
|
|
169
174
|
expect(coveModules.length).toBeGreaterThan(0)
|
|
170
175
|
})
|
|
171
176
|
|
|
172
|
-
await step('Verify map visualization is present', async () => {
|
|
173
|
-
const mapElement = canvasElement.querySelector('svg')
|
|
174
|
-
expect(mapElement).toBeInTheDocument()
|
|
175
|
-
})
|
|
176
|
-
|
|
177
177
|
console.log(` ${storyName} dashboard rendered successfully`)
|
|
178
178
|
}
|
|
179
179
|
|
|
@@ -37,22 +37,36 @@ const CONFIG_URLS = {
|
|
|
37
37
|
type MapStory = StoryObj<typeof CdcMap>
|
|
38
38
|
type DashboardStory = StoryObj<typeof Dashboard>
|
|
39
39
|
|
|
40
|
-
// Helper function to test map rendering
|
|
40
|
+
// Helper function to test map rendering (supports both SVG and canvas-based maps)
|
|
41
41
|
const testMapRendering = async (canvasElement: HTMLElement, storyName: string) => {
|
|
42
|
-
const canvas = within(canvasElement)
|
|
43
|
-
|
|
44
42
|
await step('Wait for map to render', async () => {
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
await new Promise<void>((resolve, reject) => {
|
|
44
|
+
const startTime = Date.now()
|
|
45
|
+
const timeout = 15000
|
|
46
|
+
|
|
47
|
+
const checkMap = () => {
|
|
48
|
+
const svgMap = canvasElement.querySelector('svg[role="img"]')
|
|
49
|
+
const canvasMap = canvasElement.querySelector('canvas')
|
|
50
|
+
if (svgMap || canvasMap) {
|
|
51
|
+
resolve()
|
|
52
|
+
} else if (Date.now() - startTime > timeout) {
|
|
53
|
+
reject(new Error(`Timeout: No map element (svg or canvas) found after ${timeout}ms`))
|
|
54
|
+
} else {
|
|
55
|
+
setTimeout(checkMap, 100)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
checkMap()
|
|
59
|
+
})
|
|
47
60
|
})
|
|
48
61
|
|
|
49
|
-
await step('Verify
|
|
50
|
-
const
|
|
51
|
-
|
|
62
|
+
await step('Verify map visualization is present', async () => {
|
|
63
|
+
const svgMap = canvasElement.querySelector('svg[role="img"]')
|
|
64
|
+
const canvasMap = canvasElement.querySelector('canvas')
|
|
65
|
+
expect(svgMap || canvasMap).toBeTruthy()
|
|
52
66
|
})
|
|
53
67
|
|
|
54
68
|
await step('Verify COVE module wrapper is present', async () => {
|
|
55
|
-
const coveModule = canvasElement.querySelector('.
|
|
69
|
+
const coveModule = canvasElement.querySelector('.cove-visualization')
|
|
56
70
|
expect(coveModule).toBeInTheDocument()
|
|
57
71
|
})
|
|
58
72
|
|
|
@@ -67,7 +81,7 @@ const testDashboardRendering = async (canvasElement: HTMLElement, storyName: str
|
|
|
67
81
|
const timeout = 15000
|
|
68
82
|
|
|
69
83
|
const checkDashboard = () => {
|
|
70
|
-
const dashboardElement = canvasElement.querySelector('.
|
|
84
|
+
const dashboardElement = canvasElement.querySelector('.type-dashboard')
|
|
71
85
|
if (dashboardElement) {
|
|
72
86
|
resolve()
|
|
73
87
|
} else if (Date.now() - startTime > timeout) {
|
|
@@ -81,7 +95,7 @@ const testDashboardRendering = async (canvasElement: HTMLElement, storyName: str
|
|
|
81
95
|
})
|
|
82
96
|
|
|
83
97
|
await step('Verify dashboard wrapper is present', async () => {
|
|
84
|
-
const dashboard = canvasElement.querySelector('.
|
|
98
|
+
const dashboard = canvasElement.querySelector('.type-dashboard')
|
|
85
99
|
expect(dashboard).toBeInTheDocument()
|
|
86
100
|
})
|
|
87
101
|
|
|
@@ -144,25 +158,25 @@ export const Connecticut_2022: MapStory = {
|
|
|
144
158
|
*/
|
|
145
159
|
export const All_EEE_Visualizations: StoryObj = {
|
|
146
160
|
render: () => (
|
|
147
|
-
<div className=
|
|
148
|
-
<h1 className=
|
|
161
|
+
<div className='container-fluid p-4'>
|
|
162
|
+
<h1 className='mb-4'>Eastern Equine Encephalitis - Historic Data</h1>
|
|
149
163
|
|
|
150
|
-
<section className=
|
|
164
|
+
<section className='mb-5'>
|
|
151
165
|
<h2>Cumulative Data for 2003–2024</h2>
|
|
152
166
|
<Dashboard configUrl={CONFIG_URLS.cumulativeData} />
|
|
153
167
|
</section>
|
|
154
168
|
|
|
155
|
-
<section className=
|
|
169
|
+
<section className='mb-5'>
|
|
156
170
|
<h2>Explore Human Data for 2003–2024</h2>
|
|
157
171
|
<Dashboard configUrl={CONFIG_URLS.exploreHumanData} />
|
|
158
172
|
</section>
|
|
159
173
|
|
|
160
|
-
<section className=
|
|
174
|
+
<section className='mb-5'>
|
|
161
175
|
<h2>Explore County Level Data for 2003–2024</h2>
|
|
162
176
|
<CdcMap configUrl={CONFIG_URLS.exploreCountyData} />
|
|
163
177
|
</section>
|
|
164
178
|
|
|
165
|
-
<section className=
|
|
179
|
+
<section className='mb-5'>
|
|
166
180
|
<h2>Connecticut 2022 Data</h2>
|
|
167
181
|
<CdcMap configUrl={CONFIG_URLS.ct2022} />
|
|
168
182
|
</section>
|
|
@@ -179,7 +193,7 @@ export const All_EEE_Visualizations: StoryObj = {
|
|
|
179
193
|
const timeout = 30000
|
|
180
194
|
|
|
181
195
|
const checkModules = () => {
|
|
182
|
-
const coveModules = canvasElement.querySelectorAll('.
|
|
196
|
+
const coveModules = canvasElement.querySelectorAll('.cove-visualization')
|
|
183
197
|
if (coveModules.length >= 4) {
|
|
184
198
|
resolve()
|
|
185
199
|
} else if (Date.now() - startTime > timeout) {
|
|
@@ -193,7 +207,7 @@ export const All_EEE_Visualizations: StoryObj = {
|
|
|
193
207
|
})
|
|
194
208
|
|
|
195
209
|
await step('Verify at least 4 visualizations are present', async () => {
|
|
196
|
-
const coveModules = canvasElement.querySelectorAll('.
|
|
210
|
+
const coveModules = canvasElement.querySelectorAll('.cove-visualization')
|
|
197
211
|
expect(coveModules.length).toBeGreaterThanOrEqual(4)
|
|
198
212
|
})
|
|
199
213
|
|
|
@@ -5,171 +5,176 @@ import { useEffect, useState } from 'react'
|
|
|
5
5
|
|
|
6
6
|
// Fallback step function for test descriptions
|
|
7
7
|
const step = async (description: string, fn: () => Promise<void> | void) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
console.log(`▶ ${description}`)
|
|
9
|
+
await fn()
|
|
10
|
+
console.log(`✓ ${description}`)
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const meta: Meta = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
14
|
+
title: 'Regression Tests/Pages/Excessive Alcohol Use',
|
|
15
|
+
parameters: {
|
|
16
|
+
layout: 'fullscreen',
|
|
17
|
+
docs: {
|
|
18
|
+
description: {
|
|
19
|
+
component:
|
|
20
|
+
'Stories for visualizations from the CDC Excessive Alcohol Use page (https://www.cdc.gov/alcohol/fact-sheets/states/excessive-alcohol-use-united-states.html)'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
tags: ['autodocs']
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export default meta
|
|
27
28
|
|
|
28
29
|
// Config URL from the excessive alcohol use page
|
|
29
30
|
const CONFIG_URLS = {
|
|
30
|
-
|
|
31
|
+
excessiveAlcoholUse: 'https://www.cdc.gov/alcohol/fact-sheets/states/alcohol-data-for-50-states.json'
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
// Helper to fetch config and update data URLs to use absolute cdc.gov paths
|
|
34
35
|
const useConfigWithAbsoluteDataUrl = (configUrl: string) => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
36
|
+
const [config, setConfig] = useState(null)
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
fetch(configUrl)
|
|
40
|
+
.then(res => res.json())
|
|
41
|
+
.then(data => {
|
|
42
|
+
// Convert relative data URLs to absolute cdc.gov URLs
|
|
43
|
+
if (data.dataUrl) {
|
|
44
|
+
// Handle different relative path formats (../../path or /path)
|
|
45
|
+
const dataUrl = data.dataUrl.replace(/^(\.\.\/)+/, '').replace(/^\//, '')
|
|
46
|
+
data.dataUrl = `https://www.cdc.gov/${dataUrl}`
|
|
47
|
+
}
|
|
48
|
+
if (data.dataFileName) {
|
|
49
|
+
const dataFileName = data.dataFileName.replace(/^(\.\.\/)+/, '').replace(/^\//, '')
|
|
50
|
+
data.dataFileName = `https://www.cdc.gov/${dataFileName}`
|
|
51
|
+
}
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
})
|
|
63
|
-
}
|
|
64
|
-
})
|
|
53
|
+
// For dashboard configs with multiDashboards, convert dataKey references in visualizations
|
|
54
|
+
if (data.multiDashboards) {
|
|
55
|
+
data.multiDashboards.forEach((dashboard: any) => {
|
|
56
|
+
if (dashboard.visualizations) {
|
|
57
|
+
Object.values(dashboard.visualizations).forEach((viz: any) => {
|
|
58
|
+
// Only convert dataKey if it's a URL path (starts with / or ../)
|
|
59
|
+
if (viz.dataKey && (viz.dataKey.startsWith('/') || viz.dataKey.startsWith('../'))) {
|
|
60
|
+
const dataKey = viz.dataKey.replace(/^(\.\.\/)+/, '').replace(/^\//, '')
|
|
61
|
+
viz.dataKey = `https://www.cdc.gov/${dataKey}`
|
|
65
62
|
}
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
}
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
// For dashboard configs, convert dataKey references in visualizations
|
|
69
|
+
if (data.visualizations) {
|
|
70
|
+
Object.values(data.visualizations).forEach((viz: any) => {
|
|
71
|
+
// Only convert dataKey if it's a URL path (starts with / or ../)
|
|
72
|
+
if (viz.dataKey && (viz.dataKey.startsWith('/') || viz.dataKey.startsWith('../'))) {
|
|
73
|
+
const dataKey = viz.dataKey.replace(/^(\.\.\/)+/, '').replace(/^\//, '')
|
|
74
|
+
viz.dataKey = `https://www.cdc.gov/${dataKey}`
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
}
|
|
77
78
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
79
|
+
// For dashboard configs, convert datasets only if they reference external files
|
|
80
|
+
if (data.datasets) {
|
|
81
|
+
const newDatasets = {}
|
|
82
|
+
Object.entries(data.datasets).forEach(([key, dataset]: [string, any]) => {
|
|
83
|
+
// Check if dataset has embedded data
|
|
84
|
+
const hasEmbeddedData = (dataset as any).data && Array.isArray((dataset as any).data)
|
|
85
|
+
|
|
86
|
+
// If data is embedded, keep the original key
|
|
87
|
+
if (hasEmbeddedData) {
|
|
88
|
+
newDatasets[key] = dataset
|
|
89
|
+
} else {
|
|
90
|
+
// Otherwise, convert paths to absolute URLs (but keep absolute URLs as-is)
|
|
91
|
+
const newKey = key.replace(/^(\.\.\/)+/, '').replace(/^\//, '')
|
|
92
|
+
const absoluteKey = key.startsWith('http') ? key : `https://www.cdc.gov/${newKey}`
|
|
93
|
+
|
|
94
|
+
newDatasets[absoluteKey] = {
|
|
95
|
+
...dataset,
|
|
96
|
+
dataFileName:
|
|
97
|
+
(dataset as any).dataFileName && !(dataset as any).dataFileName.startsWith('http')
|
|
98
|
+
? `https://www.cdc.gov/${(dataset as any).dataFileName
|
|
99
|
+
.replace(/^(\.\.\/)+/, '')
|
|
100
|
+
.replace(/^\//, '')}`
|
|
101
|
+
: (dataset as any).dataFileName,
|
|
102
|
+
dataUrl:
|
|
103
|
+
(dataset as any).dataUrl && !(dataset as any).dataUrl.startsWith('http')
|
|
104
|
+
? `https://www.cdc.gov/${(dataset as any).dataUrl.replace(/^(\.\.\/)+/, '').replace(/^\//, '')}`
|
|
105
|
+
: (dataset as any).dataUrl
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
data.datasets = newDatasets
|
|
110
|
+
}
|
|
106
111
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
112
|
+
// Set activeDashboard to 0 if it's null and multiDashboards exist
|
|
113
|
+
if (data.multiDashboards && data.multiDashboards.length > 0 && data.activeDashboard === null) {
|
|
114
|
+
data.activeDashboard = 0
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Log config info for debugging
|
|
118
|
+
console.log('✓ Config loaded:', {
|
|
119
|
+
type: data.type,
|
|
120
|
+
hasMultiDashboards: !!data.multiDashboards,
|
|
121
|
+
dashboardCount: data.multiDashboards?.length || 0,
|
|
122
|
+
activeDashboard: data.activeDashboard,
|
|
123
|
+
datasetCount: Object.keys(data.datasets || {}).length,
|
|
124
|
+
dashboardLabels: data.multiDashboards?.map((d: any) => d.label)
|
|
125
|
+
})
|
|
111
126
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
setConfig(data)
|
|
123
|
-
})
|
|
124
|
-
.catch(err => {
|
|
125
|
-
console.error('Failed to fetch config:', configUrl, err)
|
|
126
|
-
})
|
|
127
|
-
}, [configUrl])
|
|
128
|
-
|
|
129
|
-
return config
|
|
127
|
+
setConfig(data)
|
|
128
|
+
})
|
|
129
|
+
.catch(err => {
|
|
130
|
+
console.error('Failed to fetch config:', configUrl, err)
|
|
131
|
+
})
|
|
132
|
+
}, [configUrl])
|
|
133
|
+
|
|
134
|
+
return config
|
|
130
135
|
}
|
|
131
136
|
|
|
132
137
|
type DashboardStory = StoryObj<typeof Dashboard>
|
|
133
138
|
|
|
134
139
|
// Helper function to test dashboard rendering
|
|
135
140
|
const testDashboardRendering = async (canvasElement: HTMLElement, storyName: string) => {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
141
|
+
await step('Wait for dashboard to render', async () => {
|
|
142
|
+
await new Promise<void>((resolve, reject) => {
|
|
143
|
+
const startTime = Date.now()
|
|
144
|
+
const timeout = 30000 // Longer timeout for external data loading
|
|
145
|
+
|
|
146
|
+
const checkDashboard = () => {
|
|
147
|
+
const dashboardElement = canvasElement.querySelector('.type-dashboard')
|
|
148
|
+
const loadingDiv = canvasElement.querySelector('div')
|
|
149
|
+
|
|
150
|
+
// Log current state for debugging
|
|
151
|
+
if (!dashboardElement && loadingDiv?.textContent?.includes('Loading')) {
|
|
152
|
+
console.log('Still loading config...')
|
|
153
|
+
}
|
|
149
154
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
})
|
|
155
|
+
if (dashboardElement) {
|
|
156
|
+
resolve()
|
|
157
|
+
} else if (Date.now() - startTime > timeout) {
|
|
158
|
+
reject(new Error(`Timeout: Dashboard element not found after ${timeout}ms`))
|
|
159
|
+
} else {
|
|
160
|
+
setTimeout(checkDashboard, 100)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
checkDashboard()
|
|
160
164
|
})
|
|
165
|
+
})
|
|
161
166
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
167
|
+
await step('Verify dashboard wrapper is present', async () => {
|
|
168
|
+
const dashboard = canvasElement.querySelector('.type-dashboard')
|
|
169
|
+
expect(dashboard).toBeInTheDocument()
|
|
170
|
+
})
|
|
166
171
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
172
|
+
await step('Verify at least one visualization rendered', async () => {
|
|
173
|
+
const coveModules = canvasElement.querySelectorAll('.cove-visualization')
|
|
174
|
+
expect(coveModules.length).toBeGreaterThan(0)
|
|
175
|
+
})
|
|
171
176
|
|
|
172
|
-
|
|
177
|
+
console.log(`✓ ${storyName} dashboard rendered successfully`)
|
|
173
178
|
}
|
|
174
179
|
|
|
175
180
|
/**
|
|
@@ -185,12 +190,12 @@ const testDashboardRendering = async (canvasElement: HTMLElement, storyName: str
|
|
|
185
190
|
* - State-specific alcohol consumption trends
|
|
186
191
|
*/
|
|
187
192
|
export const Excessive_Alcohol_Use_Dashboard: DashboardStory = {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
193
|
+
render: () => {
|
|
194
|
+
const config = useConfigWithAbsoluteDataUrl(CONFIG_URLS.excessiveAlcoholUse)
|
|
195
|
+
if (!config) return <div>Loading...</div>
|
|
196
|
+
return <Dashboard config={config} />
|
|
197
|
+
},
|
|
198
|
+
play: async ({ canvasElement }) => {
|
|
199
|
+
await testDashboardRendering(canvasElement, 'Excessive Alcohol Use Dashboard')
|
|
200
|
+
}
|
|
196
201
|
}
|
|
@@ -16,7 +16,8 @@ const meta: Meta = {
|
|
|
16
16
|
layout: 'fullscreen',
|
|
17
17
|
docs: {
|
|
18
18
|
description: {
|
|
19
|
-
component:
|
|
19
|
+
component:
|
|
20
|
+
'Stories for visualizations from the CDC Pregnancy Mortality Surveillance System (PMSS) page (https://www.cdc.gov/maternal-mortality/php/pregnancy-mortality-surveillance-data/index.html)'
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
23
|
},
|
|
@@ -140,7 +141,7 @@ const testDashboardRendering = async (canvasElement: HTMLElement, storyName: str
|
|
|
140
141
|
const timeout = 20000
|
|
141
142
|
|
|
142
143
|
const checkDashboard = () => {
|
|
143
|
-
const dashboardElement = canvasElement.querySelector('.
|
|
144
|
+
const dashboardElement = canvasElement.querySelector('.type-dashboard')
|
|
144
145
|
const loadingDiv = canvasElement.querySelector('div')
|
|
145
146
|
|
|
146
147
|
// Log current state for debugging
|
|
@@ -161,12 +162,12 @@ const testDashboardRendering = async (canvasElement: HTMLElement, storyName: str
|
|
|
161
162
|
})
|
|
162
163
|
|
|
163
164
|
await step('Verify dashboard wrapper is present', async () => {
|
|
164
|
-
const dashboard = canvasElement.querySelector('.
|
|
165
|
+
const dashboard = canvasElement.querySelector('.type-dashboard')
|
|
165
166
|
expect(dashboard).toBeInTheDocument()
|
|
166
167
|
})
|
|
167
168
|
|
|
168
169
|
await step('Verify at least one visualization rendered', async () => {
|
|
169
|
-
const coveModules = canvasElement.querySelectorAll('.
|
|
170
|
+
const coveModules = canvasElement.querySelectorAll('.cove-visualization')
|
|
170
171
|
expect(coveModules.length).toBeGreaterThan(0)
|
|
171
172
|
})
|
|
172
173
|
|