Fix dashboard loading: migrate election analysis from JSON to CSV loaders#1249
Fix dashboard loading: migrate election analysis from JSON to CSV loaders#1249
Conversation
🏷️ Automatic Labeling SummaryThis PR has been automatically labeled based on the files changed and PR metadata. Applied Labels: size-xs Label Categories
For more information, see |
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
…a-exports/ from gitignore Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
… as-any in tests Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
There was a problem hiding this comment.
Pull request overview
Migrates the dashboard’s election analysis loading path from a JSON file (missing in deployed builds) to the existing CSV-based loading approach used elsewhere, by introducing election CSV sources and rebuilding loadElectionAnalysis() from CSV rows.
Changes:
- Added election forecast + coalition scenarios CSV files under
cia-data/election/. - Rewrote
loadElectionAnalysis()in both the TypeScript and dashboard JS loaders to assembleElectionAnalysisfrom CSV vialoadCSV(), and removed the dashboard loaders’ JSON loader/base URL. - Added Vitest coverage for CSV-based election analysis loading and for ensuring the CIA loader no longer exposes JSON-specific members.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/cia-data-loader-election.test.ts | Adds tests verifying election analysis is built from CSV and that JSON-specific members are not present on CIADataLoader. |
| src/browser/cia/data-loader.ts | Adds election CSV source mappings and rebuilds loadElectionAnalysis() from CSV rows (removing the JSON loader/base URL). |
| dashboard/cia-data-loader.js | Mirrors the TS loader changes for the dashboard runtime loader (CSV-based election analysis; removes JSON loader/base URL). |
| dashboard/election-predictions.js | Updates documentation comments to reflect CSV-based election analysis sourcing. |
| cia-data/election/election_forecast.csv | Introduces election forecast dataset (party seat predictions, vote share, confidence interval). |
| cia-data/election/coalition_scenarios.csv | Introduces coalition scenario dataset (probability, composition, seats, majority, risk level). |
| .gitignore | Stops ignoring data/cia-exports/. |
| const parties = forecastRows.map(r => ({ | ||
| name: r.name, | ||
| currentSeats: r.currentSeats, | ||
| predictedSeats: r.predictedSeats, | ||
| change: r.change, | ||
| voteShare: r.voteShare, | ||
| confidenceInterval: | ||
| r.confidenceMin != null && r.confidenceMax != null | ||
| ? { min: r.confidenceMin, max: r.confidenceMax } | ||
| : undefined | ||
| })); | ||
|
|
| const parties = forecastRows.map(r => ({ | ||
| name: r.name as string, | ||
| currentSeats: r.currentSeats as number, | ||
| predictedSeats: r.predictedSeats as number, | ||
| change: r.change as number, | ||
| voteShare: r.voteShare as number, | ||
| confidenceInterval: | ||
| r.confidenceMin != null && r.confidenceMax != null | ||
| ? { min: r.confidenceMin as number, max: r.confidenceMax as number } | ||
| : undefined | ||
| })); | ||
|
|
|
@copilot apply changes based on the comments in this thread |
…to reject empty CSV strings Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Fixed in |
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
There was a problem hiding this comment.
Pull request overview
Migrates the dashboard’s election analysis loading path from JSON artifacts (previously causing 404s in deployment) to the existing CSV-based loading approach used across the rest of the CIA dashboard data pipeline.
Changes:
- Reworked
loadElectionAnalysis()in both the TS and dashboard JS loaders to build the election analysis object fromcia-data/election/*.csv. - Added election forecast and coalition scenario CSV datasets under
cia-data/election/. - Added a dedicated Vitest suite covering CSV-based election analysis loading (including empty-string confidence interval edge case) and removed
data/cia-exports/from.gitignore.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/cia-data-loader-election.test.ts | Adds test coverage for CSV-based loadElectionAnalysis() and verifies JSON dependency removal. |
| src/browser/cia/data-loader.ts | Adds CSV source definitions and rebuilds loadElectionAnalysis() using CSV loaders; removes JSON loader usage. |
| dashboard/election-predictions.js | Updates inline documentation to reflect CSV-based election analysis sourcing. |
| dashboard/cia-data-loader.js | Mirrors TS loader changes for CSV-based election analysis; removes JSON loader; updates module docs. |
| cia-data/election/election_forecast.csv | Adds the election forecast dataset consumed by loaders. |
| cia-data/election/coalition_scenarios.csv | Adds coalition scenario dataset consumed by loaders. |
| .gitignore | Stops ignoring data/cia-exports/ (previous JSON export location). |
| const parties = forecastRows.map(r => ({ | ||
| name: r.name as string, | ||
| currentSeats: r.currentSeats as number, | ||
| predictedSeats: r.predictedSeats as number, | ||
| change: r.change as number, | ||
| voteShare: r.voteShare as number, | ||
| confidenceInterval: | ||
| typeof r.confidenceMin === 'number' && Number.isFinite(r.confidenceMin) && | ||
| typeof r.confidenceMax === 'number' && Number.isFinite(r.confidenceMax) | ||
| ? { min: r.confidenceMin, max: r.confidenceMax } | ||
| : undefined | ||
| })); | ||
|
|
||
| const coalitionScenarios = scenarioRows.map(r => ({ | ||
| name: r.name as string, | ||
| probability: r.probability as number, | ||
| composition: (r.composition as string).split(',').map(s => s.trim()), | ||
| totalSeats: r.totalSeats as number, | ||
| majority: String(r.majority).toLowerCase() === 'true', | ||
| riskLevel: r.riskLevel as string | ||
| })); | ||
|
|
| const parties = forecastRows.map(r => ({ | ||
| name: r.name, | ||
| currentSeats: r.currentSeats, | ||
| predictedSeats: r.predictedSeats, | ||
| change: r.change, | ||
| voteShare: r.voteShare, | ||
| confidenceInterval: | ||
| typeof r.confidenceMin === 'number' && Number.isFinite(r.confidenceMin) && | ||
| typeof r.confidenceMax === 'number' && Number.isFinite(r.confidenceMax) | ||
| ? { min: r.confidenceMin, max: r.confidenceMax } | ||
| : undefined | ||
| })); | ||
|
|
||
| const coalitionScenarios = scenarioRows.map(r => ({ | ||
| name: r.name, | ||
| probability: r.probability, | ||
| composition: String(r.composition).split(',').map(s => s.trim()), | ||
| totalSeats: r.totalSeats, | ||
| majority: String(r.majority).toLowerCase() === 'true', | ||
| riskLevel: r.riskLevel | ||
| })); | ||
|
|
| @@ -80,7 +75,7 @@ | |||
| * return await this.loadLocal(category); // Tier 1: Local CSV | |||
| * } catch (err) { | |||
| * try { | |||
| * return await this.loadJSON(category); // Tier 2: Local JSON | |||
| * return await this.loadCSV(category); // Tier 2: CSV fallback | |||
| * } catch (err) { | |||
| * return await this.loadRemote(category); // Tier 3: GitHub | |||
| * } | |||
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Implemented in
Validation run: targeted Vitest suite (10/10), browser TypeScript check, and ESLint on modified files all pass. No UI was changed in this patch, so there is no UI screenshot to provide. |
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
There was a problem hiding this comment.
Pull request overview
Migrates the election analysis data path away from JSON artifacts and into the existing CSV-based loader pipeline, aligning election predictions with the rest of the dashboard’s data ingestion model.
Changes:
- Implement
loadElectionAnalysis()using CSV sources (election_forecast.csv,coalition_scenarios.csv) in both the TS browser loader and the dashboard JS loader. - Add election CSV datasets under
cia-data/election/and add targeted Vitest coverage for numeric coercion and invalid/blank CSV cells. - Update dashboard-side documentation/comments to remove references to
election-analysis.jsonand removedata/cia-exports/from.gitignore.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/cia-data-loader-election.test.ts | Adds tests validating CSV-based election analysis loading and numeric field handling. |
| src/browser/cia/data-loader.ts | Removes JSON loader usage and builds ElectionAnalysis from CSV rows with coercion/validation. |
| dashboard/election-predictions.js | Updates comments to reflect CSV-based election analysis inputs. |
| dashboard/cia-data-loader.js | Mirrors TS loader changes: removes JSON loader and builds election analysis from CSV sources. |
| cia-data/election/election_forecast.csv | Introduces the election forecast CSV source data. |
| cia-data/election/coalition_scenarios.csv | Introduces the coalition scenarios CSV source data. |
| .gitignore | Stops ignoring data/cia-exports/ (previous JSON export location). |
| majority: String(r.majority).toLowerCase() === 'true', | ||
| riskLevel: String(r.riskLevel ?? '') | ||
| }]; |
| totalSeats, | ||
| majority: String(r.majority).toLowerCase() === 'true', | ||
| riskLevel: String(r.riskLevel ?? '') | ||
| }]; |
| describe('no JSON dependency', () => { | ||
| it('should not have a loadJSON method', () => { | ||
| const loader = new CIADataLoader(); | ||
| expect('loadJSON' in loader).toBe(false); | ||
| }); | ||
|
|
||
| it('should not have a jsonBaseURL property', () => { | ||
| const loader = new CIADataLoader(); | ||
| expect('jsonBaseURL' in loader).toBe(false); |
| it('should not have a jsonBaseURL property', () => { | ||
| const loader = new CIADataLoader(); | ||
| expect('jsonBaseURL' in loader).toBe(false); |
|
@copilot apply changes based on the comments in this thread |
…ests Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Applied in
Validation passed: baseline No UI changes were made in this patch, so no screenshot is applicable. |
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
There was a problem hiding this comment.
Pull request overview
Migrates election analysis loading for both the TypeScript browser bundle and the dashboard JS loader away from election-analysis.json to the same CSV-based loading approach used for other CIA dashboard datasets.
Changes:
- Implement CSV-based
loadElectionAnalysis()in bothsrc/browser/cia/data-loader.tsanddashboard/cia-data-loader.js, removing the JSON loader/fallback. - Add election CSV datasets (
election_forecast.csv,coalition_scenarios.csv) and a dedicated Vitest suite validating parsing and fetch behavior. - Update dashboard documentation comments and adjust
.gitignoreto stop ignoringdata/cia-exports/.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/cia-data-loader-election.test.ts | Adds tests ensuring election analysis is built from CSV fetches and invalid rows are dropped. |
| src/browser/cia/data-loader.ts | Adds election CSV sources and implements CSV-based loadElectionAnalysis(); removes JSON loading path. |
| dashboard/election-predictions.js | Updates inline documentation references from JSON to CSV-based sources. |
| dashboard/cia-data-loader.js | Mirrors TS loader changes: removes JSON loading and builds election analysis from CSV. |
| cia-data/election/election_forecast.csv | Adds party forecast CSV used by election analysis loader. |
| cia-data/election/coalition_scenarios.csv | Adds coalition scenarios CSV used by election analysis loader. |
| .gitignore | Stops ignoring data/cia-exports/. |
| this.loadCSV(CIADataLoader.CSV_SOURCES.electionForecast.local), | ||
| this.loadCSV(CIADataLoader.CSV_SOURCES.coalitionScenarios.local) | ||
| ]); | ||
|
|
| * Render key factors affecting the election | ||
| * NOTE: Reserved for future implementation - requires adding <div id="key-factors"></div> to HTML | ||
| * and calling this method from dashboard-init.js. The data is available in election-analysis.json. | ||
| * and calling this method from dashboard-init.js. The data is built from election CSV sources. |
| * Get election date formatted | ||
| * NOTE: Reserved for future implementation - can be used to display election date in dashboard header. | ||
| * The data is available as electionDate in election-analysis.json. | ||
| * The data is available as electionDate from election CSV sources. |
| describe('CSV_SOURCES', () => { | ||
| it('should include election forecast and coalition scenarios', () => { | ||
| expect(CIADataLoader.CSV_SOURCES.electionForecast).toBeDefined(); | ||
| expect(CIADataLoader.CSV_SOURCES.electionForecast.local).toBe( | ||
| 'election/election_forecast.csv' | ||
| ); | ||
| expect(CIADataLoader.CSV_SOURCES.coalitionScenarios).toBeDefined(); | ||
| expect(CIADataLoader.CSV_SOURCES.coalitionScenarios.local).toBe( | ||
| 'election/coalition_scenarios.csv' | ||
| ); | ||
| }); | ||
| }); | ||
|
|
🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.