euparliamentmonitor 0.8.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.
- package/LICENSE +201 -0
- package/README.md +1005 -0
- package/SECURITY.md +151 -0
- package/package.json +131 -0
- package/scripts/constants/committee-indicator-map.d.ts +199 -0
- package/scripts/constants/committee-indicator-map.d.ts.map +1 -0
- package/scripts/constants/committee-indicator-map.js +1224 -0
- package/scripts/constants/committee-indicator-map.js.map +1 -0
- package/scripts/constants/config.d.ts +38 -0
- package/scripts/constants/config.d.ts.map +1 -0
- package/scripts/constants/config.js +66 -0
- package/scripts/constants/config.js.map +1 -0
- package/scripts/constants/language-articles.d.ts +84 -0
- package/scripts/constants/language-articles.d.ts.map +1 -0
- package/scripts/constants/language-articles.js +6771 -0
- package/scripts/constants/language-articles.js.map +1 -0
- package/scripts/constants/language-core.d.ts +38 -0
- package/scripts/constants/language-core.d.ts.map +1 -0
- package/scripts/constants/language-core.js +90 -0
- package/scripts/constants/language-core.js.map +1 -0
- package/scripts/constants/language-ui.d.ts +82 -0
- package/scripts/constants/language-ui.d.ts.map +1 -0
- package/scripts/constants/language-ui.js +889 -0
- package/scripts/constants/language-ui.js.map +1 -0
- package/scripts/constants/languages.d.ts +14 -0
- package/scripts/constants/languages.d.ts.map +1 -0
- package/scripts/constants/languages.js +15 -0
- package/scripts/constants/languages.js.map +1 -0
- package/scripts/generators/analysis-builders.d.ts +266 -0
- package/scripts/generators/analysis-builders.d.ts.map +1 -0
- package/scripts/generators/analysis-builders.js +2903 -0
- package/scripts/generators/analysis-builders.js.map +1 -0
- package/scripts/generators/breaking-content.d.ts +45 -0
- package/scripts/generators/breaking-content.d.ts.map +1 -0
- package/scripts/generators/breaking-content.js +530 -0
- package/scripts/generators/breaking-content.js.map +1 -0
- package/scripts/generators/committee-helpers.d.ts +54 -0
- package/scripts/generators/committee-helpers.d.ts.map +1 -0
- package/scripts/generators/committee-helpers.js +154 -0
- package/scripts/generators/committee-helpers.js.map +1 -0
- package/scripts/generators/dashboard-content.d.ts +95 -0
- package/scripts/generators/dashboard-content.d.ts.map +1 -0
- package/scripts/generators/dashboard-content.js +630 -0
- package/scripts/generators/dashboard-content.js.map +1 -0
- package/scripts/generators/deep-analysis-content.d.ts +23 -0
- package/scripts/generators/deep-analysis-content.d.ts.map +1 -0
- package/scripts/generators/deep-analysis-content.js +831 -0
- package/scripts/generators/deep-analysis-content.js.map +1 -0
- package/scripts/generators/mindmap-content.d.ts +55 -0
- package/scripts/generators/mindmap-content.d.ts.map +1 -0
- package/scripts/generators/mindmap-content.js +512 -0
- package/scripts/generators/mindmap-content.js.map +1 -0
- package/scripts/generators/motions-content.d.ts +50 -0
- package/scripts/generators/motions-content.d.ts.map +1 -0
- package/scripts/generators/motions-content.js +391 -0
- package/scripts/generators/motions-content.js.map +1 -0
- package/scripts/generators/news-enhanced.d.ts +14 -0
- package/scripts/generators/news-enhanced.d.ts.map +1 -0
- package/scripts/generators/news-enhanced.js +169 -0
- package/scripts/generators/news-enhanced.js.map +1 -0
- package/scripts/generators/news-indexes.d.ts +31 -0
- package/scripts/generators/news-indexes.d.ts.map +1 -0
- package/scripts/generators/news-indexes.js +410 -0
- package/scripts/generators/news-indexes.js.map +1 -0
- package/scripts/generators/pipeline/fetch-stage.d.ts +352 -0
- package/scripts/generators/pipeline/fetch-stage.d.ts.map +1 -0
- package/scripts/generators/pipeline/fetch-stage.js +1522 -0
- package/scripts/generators/pipeline/fetch-stage.js.map +1 -0
- package/scripts/generators/pipeline/generate-stage.d.ts +43 -0
- package/scripts/generators/pipeline/generate-stage.d.ts.map +1 -0
- package/scripts/generators/pipeline/generate-stage.js +204 -0
- package/scripts/generators/pipeline/generate-stage.js.map +1 -0
- package/scripts/generators/pipeline/output-stage.d.ts +48 -0
- package/scripts/generators/pipeline/output-stage.d.ts.map +1 -0
- package/scripts/generators/pipeline/output-stage.js +145 -0
- package/scripts/generators/pipeline/output-stage.js.map +1 -0
- package/scripts/generators/pipeline/transform-stage.d.ts +57 -0
- package/scripts/generators/pipeline/transform-stage.d.ts.map +1 -0
- package/scripts/generators/pipeline/transform-stage.js +111 -0
- package/scripts/generators/pipeline/transform-stage.js.map +1 -0
- package/scripts/generators/propositions-content.d.ts +29 -0
- package/scripts/generators/propositions-content.d.ts.map +1 -0
- package/scripts/generators/propositions-content.js +90 -0
- package/scripts/generators/propositions-content.js.map +1 -0
- package/scripts/generators/sankey-content.d.ts +45 -0
- package/scripts/generators/sankey-content.d.ts.map +1 -0
- package/scripts/generators/sankey-content.js +227 -0
- package/scripts/generators/sankey-content.js.map +1 -0
- package/scripts/generators/sitemap.d.ts +66 -0
- package/scripts/generators/sitemap.d.ts.map +1 -0
- package/scripts/generators/sitemap.js +562 -0
- package/scripts/generators/sitemap.js.map +1 -0
- package/scripts/generators/strategies/article-strategy.d.ts +146 -0
- package/scripts/generators/strategies/article-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/article-strategy.js +4 -0
- package/scripts/generators/strategies/article-strategy.js.map +1 -0
- package/scripts/generators/strategies/breaking-news-strategy.d.ts +64 -0
- package/scripts/generators/strategies/breaking-news-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/breaking-news-strategy.js +246 -0
- package/scripts/generators/strategies/breaking-news-strategy.js.map +1 -0
- package/scripts/generators/strategies/committee-reports-strategy.d.ts +93 -0
- package/scripts/generators/strategies/committee-reports-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/committee-reports-strategy.js +447 -0
- package/scripts/generators/strategies/committee-reports-strategy.js.map +1 -0
- package/scripts/generators/strategies/month-ahead-strategy.d.ts +60 -0
- package/scripts/generators/strategies/month-ahead-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/month-ahead-strategy.js +175 -0
- package/scripts/generators/strategies/month-ahead-strategy.js.map +1 -0
- package/scripts/generators/strategies/monthly-review-strategy.d.ts +66 -0
- package/scripts/generators/strategies/monthly-review-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/monthly-review-strategy.js +204 -0
- package/scripts/generators/strategies/monthly-review-strategy.js.map +1 -0
- package/scripts/generators/strategies/motions-strategy.d.ts +61 -0
- package/scripts/generators/strategies/motions-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/motions-strategy.js +215 -0
- package/scripts/generators/strategies/motions-strategy.js.map +1 -0
- package/scripts/generators/strategies/propositions-strategy.d.ts +60 -0
- package/scripts/generators/strategies/propositions-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/propositions-strategy.js +257 -0
- package/scripts/generators/strategies/propositions-strategy.js.map +1 -0
- package/scripts/generators/strategies/week-ahead-strategy.d.ts +57 -0
- package/scripts/generators/strategies/week-ahead-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/week-ahead-strategy.js +178 -0
- package/scripts/generators/strategies/week-ahead-strategy.js.map +1 -0
- package/scripts/generators/strategies/weekly-review-strategy.d.ts +63 -0
- package/scripts/generators/strategies/weekly-review-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/weekly-review-strategy.js +211 -0
- package/scripts/generators/strategies/weekly-review-strategy.js.map +1 -0
- package/scripts/generators/swot-content.d.ts +42 -0
- package/scripts/generators/swot-content.d.ts.map +1 -0
- package/scripts/generators/swot-content.js +366 -0
- package/scripts/generators/swot-content.js.map +1 -0
- package/scripts/generators/week-ahead-content.d.ts +103 -0
- package/scripts/generators/week-ahead-content.d.ts.map +1 -0
- package/scripts/generators/week-ahead-content.js +610 -0
- package/scripts/generators/week-ahead-content.js.map +1 -0
- package/scripts/index.d.ts +40 -0
- package/scripts/index.d.ts.map +1 -0
- package/scripts/index.js +53 -0
- package/scripts/index.js.map +1 -0
- package/scripts/mcp/ep-mcp-client.d.ts +471 -0
- package/scripts/mcp/ep-mcp-client.d.ts.map +1 -0
- package/scripts/mcp/ep-mcp-client.js +734 -0
- package/scripts/mcp/ep-mcp-client.js.map +1 -0
- package/scripts/mcp/mcp-connection.d.ts +264 -0
- package/scripts/mcp/mcp-connection.d.ts.map +1 -0
- package/scripts/mcp/mcp-connection.js +790 -0
- package/scripts/mcp/mcp-connection.js.map +1 -0
- package/scripts/mcp/mcp-health.d.ts +75 -0
- package/scripts/mcp/mcp-health.d.ts.map +1 -0
- package/scripts/mcp/mcp-health.js +78 -0
- package/scripts/mcp/mcp-health.js.map +1 -0
- package/scripts/mcp/mcp-retry.d.ts +94 -0
- package/scripts/mcp/mcp-retry.d.ts.map +1 -0
- package/scripts/mcp/mcp-retry.js +127 -0
- package/scripts/mcp/mcp-retry.js.map +1 -0
- package/scripts/mcp/wb-mcp-client.d.ts +38 -0
- package/scripts/mcp/wb-mcp-client.d.ts.map +1 -0
- package/scripts/mcp/wb-mcp-client.js +112 -0
- package/scripts/mcp/wb-mcp-client.js.map +1 -0
- package/scripts/templates/article-template.d.ts +9 -0
- package/scripts/templates/article-template.d.ts.map +1 -0
- package/scripts/templates/article-template.js +378 -0
- package/scripts/templates/article-template.js.map +1 -0
- package/scripts/templates/section-builders.d.ts +28 -0
- package/scripts/templates/section-builders.d.ts.map +1 -0
- package/scripts/templates/section-builders.js +142 -0
- package/scripts/templates/section-builders.js.map +1 -0
- package/scripts/types/analysis.d.ts +115 -0
- package/scripts/types/analysis.d.ts.map +1 -0
- package/scripts/types/analysis.js +4 -0
- package/scripts/types/analysis.js.map +1 -0
- package/scripts/types/common.d.ts +584 -0
- package/scripts/types/common.d.ts.map +1 -0
- package/scripts/types/common.js +96 -0
- package/scripts/types/common.js.map +1 -0
- package/scripts/types/generation.d.ts +104 -0
- package/scripts/types/generation.d.ts.map +1 -0
- package/scripts/types/generation.js +4 -0
- package/scripts/types/generation.js.map +1 -0
- package/scripts/types/index.d.ts +24 -0
- package/scripts/types/index.d.ts.map +1 -0
- package/scripts/types/index.js +16 -0
- package/scripts/types/index.js.map +1 -0
- package/scripts/types/intelligence.d.ts +129 -0
- package/scripts/types/intelligence.d.ts.map +1 -0
- package/scripts/types/intelligence.js +4 -0
- package/scripts/types/intelligence.js.map +1 -0
- package/scripts/types/mcp.d.ts +418 -0
- package/scripts/types/mcp.d.ts.map +1 -0
- package/scripts/types/mcp.js +4 -0
- package/scripts/types/mcp.js.map +1 -0
- package/scripts/types/parliament.d.ts +388 -0
- package/scripts/types/parliament.d.ts.map +1 -0
- package/scripts/types/parliament.js +4 -0
- package/scripts/types/parliament.js.map +1 -0
- package/scripts/types/quality.d.ts +114 -0
- package/scripts/types/quality.d.ts.map +1 -0
- package/scripts/types/quality.js +4 -0
- package/scripts/types/quality.js.map +1 -0
- package/scripts/types/stakeholder.d.ts +88 -0
- package/scripts/types/stakeholder.d.ts.map +1 -0
- package/scripts/types/stakeholder.js +16 -0
- package/scripts/types/stakeholder.js.map +1 -0
- package/scripts/types/visualization.d.ts +708 -0
- package/scripts/types/visualization.d.ts.map +1 -0
- package/scripts/types/visualization.js +4 -0
- package/scripts/types/visualization.js.map +1 -0
- package/scripts/types/world-bank.d.ts +85 -0
- package/scripts/types/world-bank.d.ts.map +1 -0
- package/scripts/types/world-bank.js +4 -0
- package/scripts/types/world-bank.js.map +1 -0
- package/scripts/utils/article-category.d.ts +18 -0
- package/scripts/utils/article-category.d.ts.map +1 -0
- package/scripts/utils/article-category.js +49 -0
- package/scripts/utils/article-category.js.map +1 -0
- package/scripts/utils/article-quality-scorer.d.ts +87 -0
- package/scripts/utils/article-quality-scorer.d.ts.map +1 -0
- package/scripts/utils/article-quality-scorer.js +1048 -0
- package/scripts/utils/article-quality-scorer.js.map +1 -0
- package/scripts/utils/content-metadata.d.ts +34 -0
- package/scripts/utils/content-metadata.d.ts.map +1 -0
- package/scripts/utils/content-metadata.js +249 -0
- package/scripts/utils/content-metadata.js.map +1 -0
- package/scripts/utils/content-validator.d.ts +94 -0
- package/scripts/utils/content-validator.d.ts.map +1 -0
- package/scripts/utils/content-validator.js +489 -0
- package/scripts/utils/content-validator.js.map +1 -0
- package/scripts/utils/copy-test-reports.d.ts +9 -0
- package/scripts/utils/copy-test-reports.d.ts.map +1 -0
- package/scripts/utils/copy-test-reports.js +508 -0
- package/scripts/utils/copy-test-reports.js.map +1 -0
- package/scripts/utils/file-utils.d.ts +144 -0
- package/scripts/utils/file-utils.d.ts.map +1 -0
- package/scripts/utils/file-utils.js +374 -0
- package/scripts/utils/file-utils.js.map +1 -0
- package/scripts/utils/fix-articles.d.ts +27 -0
- package/scripts/utils/fix-articles.d.ts.map +1 -0
- package/scripts/utils/fix-articles.js +510 -0
- package/scripts/utils/fix-articles.js.map +1 -0
- package/scripts/utils/generate-docs-index.d.ts +8 -0
- package/scripts/utils/generate-docs-index.d.ts.map +1 -0
- package/scripts/utils/generate-docs-index.js +275 -0
- package/scripts/utils/generate-docs-index.js.map +1 -0
- package/scripts/utils/html-sanitize.d.ts +18 -0
- package/scripts/utils/html-sanitize.d.ts.map +1 -0
- package/scripts/utils/html-sanitize.js +57 -0
- package/scripts/utils/html-sanitize.js.map +1 -0
- package/scripts/utils/intelligence-analysis.d.ts +173 -0
- package/scripts/utils/intelligence-analysis.d.ts.map +1 -0
- package/scripts/utils/intelligence-analysis.js +936 -0
- package/scripts/utils/intelligence-analysis.js.map +1 -0
- package/scripts/utils/intelligence-index.d.ts +126 -0
- package/scripts/utils/intelligence-index.d.ts.map +1 -0
- package/scripts/utils/intelligence-index.js +731 -0
- package/scripts/utils/intelligence-index.js.map +1 -0
- package/scripts/utils/metadata-utils.d.ts +14 -0
- package/scripts/utils/metadata-utils.d.ts.map +1 -0
- package/scripts/utils/metadata-utils.js +18 -0
- package/scripts/utils/metadata-utils.js.map +1 -0
- package/scripts/utils/news-metadata.d.ts +47 -0
- package/scripts/utils/news-metadata.d.ts.map +1 -0
- package/scripts/utils/news-metadata.js +259 -0
- package/scripts/utils/news-metadata.js.map +1 -0
- package/scripts/utils/validate-articles.d.ts +2 -0
- package/scripts/utils/validate-articles.d.ts.map +1 -0
- package/scripts/utils/validate-articles.js +284 -0
- package/scripts/utils/validate-articles.js.map +1 -0
- package/scripts/utils/validate-ep-api.d.ts +51 -0
- package/scripts/utils/validate-ep-api.d.ts.map +1 -0
- package/scripts/utils/validate-ep-api.js +160 -0
- package/scripts/utils/validate-ep-api.js.map +1 -0
- package/scripts/utils/world-bank-data.d.ts +84 -0
- package/scripts/utils/world-bank-data.d.ts.map +1 -0
- package/scripts/utils/world-bank-data.js +311 -0
- package/scripts/utils/world-bank-data.js.map +1 -0
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2024-2026 Hack23 AB
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* @module Generators/DashboardContent
|
|
5
|
+
* @description Pure functions for building dashboard HTML sections with
|
|
6
|
+
* metric cards and chart containers. Designed for agentic workflows to
|
|
7
|
+
* extend any article type with data dashboards using data from European
|
|
8
|
+
* Parliament MCP, World Bank API, or other data sources.
|
|
9
|
+
*
|
|
10
|
+
* Dashboard components:
|
|
11
|
+
* - **Metric cards**: Key performance indicators with trends
|
|
12
|
+
* - **Chart containers**: Canvas elements with embedded Chart.js configuration
|
|
13
|
+
* as data attributes, ready for client-side hydration
|
|
14
|
+
* - **Coalition panels**: Radar charts showing political group alignment
|
|
15
|
+
* - **Pipeline panels**: Bar charts showing legislative procedure status
|
|
16
|
+
* - **Trend panels**: Sparkline charts showing activity over time
|
|
17
|
+
* - **Stakeholder scorecards**: Color-coded impact grids
|
|
18
|
+
*
|
|
19
|
+
* Chart configurations are embedded as JSON in `data-chart-config` attributes
|
|
20
|
+
* on `<canvas>` elements. An external client-side initialization script
|
|
21
|
+
* provided by the embedding application can hydrate these using Chart.js
|
|
22
|
+
* at runtime by reading the `data-chart-config` attributes.
|
|
23
|
+
*/
|
|
24
|
+
import { escapeHTML } from '../utils/file-utils.js';
|
|
25
|
+
import { getLocalizedString, DASHBOARD_STRINGS, DASHBOARD_BUILDER_STRINGS, } from '../constants/languages.js';
|
|
26
|
+
// ─── Sub-section builders ────────────────────────────────────────────────────
|
|
27
|
+
/**
|
|
28
|
+
* Build a single metric card HTML.
|
|
29
|
+
*
|
|
30
|
+
* @param metric - Metric data
|
|
31
|
+
* @param strings - Localized dashboard strings
|
|
32
|
+
* @returns HTML string for one metric card
|
|
33
|
+
*/
|
|
34
|
+
function buildMetricCard(metric, strings) {
|
|
35
|
+
const trendHtml = buildTrendIndicator(metric, strings);
|
|
36
|
+
const unitHtml = metric.unit
|
|
37
|
+
? ` <span class="metric-unit">${escapeHTML(metric.unit)}</span>`
|
|
38
|
+
: '';
|
|
39
|
+
return `<div class="metric-card">
|
|
40
|
+
<span class="metric-label">${escapeHTML(metric.label)}</span>
|
|
41
|
+
<span class="metric-value">${escapeHTML(metric.value)}${unitHtml}</span>
|
|
42
|
+
${trendHtml}
|
|
43
|
+
</div>`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Derive trend direction from an explicit trend value or numeric change.
|
|
47
|
+
*
|
|
48
|
+
* @param trend - Explicit trend or undefined
|
|
49
|
+
* @param change - Numeric percentage change or undefined
|
|
50
|
+
* @returns Resolved trend direction
|
|
51
|
+
*/
|
|
52
|
+
function resolveTrend(trend, change) {
|
|
53
|
+
if (trend)
|
|
54
|
+
return trend;
|
|
55
|
+
if (change !== undefined && change > 0)
|
|
56
|
+
return 'up';
|
|
57
|
+
if (change !== undefined && change < 0)
|
|
58
|
+
return 'down';
|
|
59
|
+
return 'stable';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Resolve the CSS class and symbol for a trend direction.
|
|
63
|
+
*
|
|
64
|
+
* @param trend - Resolved trend direction
|
|
65
|
+
* @returns Tuple of CSS class and display symbol
|
|
66
|
+
*/
|
|
67
|
+
function trendPresentation(trend) {
|
|
68
|
+
switch (trend) {
|
|
69
|
+
case 'up':
|
|
70
|
+
return ['metric-trend-up', '↑'];
|
|
71
|
+
case 'down':
|
|
72
|
+
return ['metric-trend-down', '↓'];
|
|
73
|
+
case 'stable':
|
|
74
|
+
return ['metric-trend-stable', '→'];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build trend indicator HTML for a metric.
|
|
79
|
+
*
|
|
80
|
+
* @param metric - Metric with optional trend and change
|
|
81
|
+
* @param strings - Localized dashboard strings
|
|
82
|
+
* @returns HTML string for trend indicator or empty string
|
|
83
|
+
*/
|
|
84
|
+
function buildTrendIndicator(metric, strings) {
|
|
85
|
+
if (!metric.trend && metric.change === undefined)
|
|
86
|
+
return '';
|
|
87
|
+
const trend = resolveTrend(metric.trend, metric.change);
|
|
88
|
+
const [trendClass, trendSymbol] = trendPresentation(trend);
|
|
89
|
+
const changeText = metric.change !== undefined
|
|
90
|
+
? ` ${metric.change > 0 ? '+' : ''}${metric.change.toFixed(1)}%`
|
|
91
|
+
: '';
|
|
92
|
+
const directionLabel = trend === 'up' ? strings.trendUp : trend === 'down' ? strings.trendDown : strings.trendStable;
|
|
93
|
+
const ariaLabel = `${strings.trendPrefix} ${directionLabel}${changeText}`;
|
|
94
|
+
return `<span class="${escapeHTML(trendClass)}" aria-label="${escapeHTML(ariaLabel)}">${trendSymbol}${escapeHTML(changeText)}</span>`;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Build a metrics grid from an array of metrics.
|
|
98
|
+
*
|
|
99
|
+
* @param metrics - Array of metric data
|
|
100
|
+
* @param strings - Localized dashboard strings
|
|
101
|
+
* @returns HTML string for the metrics grid
|
|
102
|
+
*/
|
|
103
|
+
function buildMetricsGrid(metrics, strings) {
|
|
104
|
+
if (metrics.length === 0)
|
|
105
|
+
return '';
|
|
106
|
+
const cards = metrics.map((m) => buildMetricCard(m, strings)).join('\n ');
|
|
107
|
+
return `<div class="metrics-grid">
|
|
108
|
+
${cards}
|
|
109
|
+
</div>`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Build a chart container with embedded configuration.
|
|
113
|
+
* The chart configuration is serialized as JSON in a `data-chart-config`
|
|
114
|
+
* attribute, ready for client-side hydration by Chart.js.
|
|
115
|
+
*
|
|
116
|
+
* A `<noscript>` fallback provides an accessible data table.
|
|
117
|
+
*
|
|
118
|
+
* @param chart - Chart configuration
|
|
119
|
+
* @param panelIndex - Panel index for unique canvas ID
|
|
120
|
+
* @param strings - Localized strings
|
|
121
|
+
* @returns HTML string for chart container
|
|
122
|
+
*/
|
|
123
|
+
function buildChartContainer(chart, panelIndex, strings) {
|
|
124
|
+
const canvasId = `dashboard-chart-${panelIndex}`;
|
|
125
|
+
const safeConfig = escapeHTML(JSON.stringify(chart));
|
|
126
|
+
const titleHtml = chart.title ? `<h4 class="chart-title">${escapeHTML(chart.title)}</h4>` : '';
|
|
127
|
+
const fallbackTable = buildChartFallbackTable(chart, strings);
|
|
128
|
+
return `<div class="chart-container">
|
|
129
|
+
${titleHtml}
|
|
130
|
+
<canvas id="${canvasId}" class="dashboard-chart" data-chart-config="${safeConfig}" role="img" aria-label="${escapeHTML(chart.title ?? strings.chartLabel)}"></canvas>
|
|
131
|
+
<noscript>
|
|
132
|
+
${fallbackTable}
|
|
133
|
+
</noscript>
|
|
134
|
+
</div>`;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Build an accessible fallback data table for a chart.
|
|
138
|
+
* Displayed when JavaScript is disabled.
|
|
139
|
+
*
|
|
140
|
+
* @param chart - Chart configuration
|
|
141
|
+
* @param strings - Localized strings
|
|
142
|
+
* @returns HTML table string
|
|
143
|
+
*/
|
|
144
|
+
function buildChartFallbackTable(chart, strings) {
|
|
145
|
+
const labels = chart.data.labels;
|
|
146
|
+
const datasets = chart.data.datasets;
|
|
147
|
+
if (labels.length === 0 || datasets.length === 0) {
|
|
148
|
+
return `<p class="chart-no-data">${escapeHTML(strings.noChartData)}</p>`;
|
|
149
|
+
}
|
|
150
|
+
const headerCells = datasets.map((ds) => `<th scope="col">${escapeHTML(ds.label)}</th>`).join('');
|
|
151
|
+
const header = `<tr><th scope="col">${escapeHTML(strings.categoryLabel)}</th>${headerCells}</tr>`;
|
|
152
|
+
const rows = labels
|
|
153
|
+
.map((label, i) => {
|
|
154
|
+
const cells = datasets
|
|
155
|
+
.map((ds) => {
|
|
156
|
+
const val = ds.data.at(i);
|
|
157
|
+
return `<td>${val !== undefined ? escapeHTML(String(val)) : '—'}</td>`;
|
|
158
|
+
})
|
|
159
|
+
.join('');
|
|
160
|
+
return `<tr><th scope="row">${escapeHTML(label)}</th>${cells}</tr>`;
|
|
161
|
+
})
|
|
162
|
+
.join('\n ');
|
|
163
|
+
return `<table class="chart-fallback-table" role="table">
|
|
164
|
+
<thead>${header}</thead>
|
|
165
|
+
<tbody>
|
|
166
|
+
${rows}
|
|
167
|
+
</tbody>
|
|
168
|
+
</table>`;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Build a single dashboard panel HTML.
|
|
172
|
+
*
|
|
173
|
+
* @param panel - Panel configuration
|
|
174
|
+
* @param index - Panel index for unique IDs
|
|
175
|
+
* @param strings - Localized strings
|
|
176
|
+
* @returns HTML string for one panel
|
|
177
|
+
*/
|
|
178
|
+
function buildDashboardPanel(panel, index, strings) {
|
|
179
|
+
const metricsHtml = panel.metrics ? buildMetricsGrid(panel.metrics, strings) : '';
|
|
180
|
+
const chartHtml = panel.chart ? buildChartContainer(panel.chart, index, strings) : '';
|
|
181
|
+
if (!metricsHtml && !chartHtml)
|
|
182
|
+
return '';
|
|
183
|
+
return `<div class="dashboard-panel" role="region" aria-label="${escapeHTML(panel.title)}">
|
|
184
|
+
<h3 class="panel-title">${escapeHTML(panel.title)}</h3>
|
|
185
|
+
${metricsHtml}
|
|
186
|
+
${chartHtml}
|
|
187
|
+
</div>`;
|
|
188
|
+
}
|
|
189
|
+
// ─── Political intelligence panel builders ───────────────────────────────────
|
|
190
|
+
/**
|
|
191
|
+
* Map a coalition shift indicator to its CSS class.
|
|
192
|
+
*
|
|
193
|
+
* @param shift - Shift direction
|
|
194
|
+
* @returns CSS class string
|
|
195
|
+
*/
|
|
196
|
+
function coalitionShiftClass(shift) {
|
|
197
|
+
switch (shift) {
|
|
198
|
+
case 'strengthening':
|
|
199
|
+
return 'coalition-strengthening';
|
|
200
|
+
case 'weakening':
|
|
201
|
+
return 'coalition-weakening';
|
|
202
|
+
case 'stable':
|
|
203
|
+
return 'coalition-stable';
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Build a coalition dynamics panel as a self-contained HTML section.
|
|
208
|
+
* Renders a radar chart configuration (Chart.js) embedded as a data attribute,
|
|
209
|
+
* with a `<noscript>` fallback table listing each bloc's alignment score.
|
|
210
|
+
*
|
|
211
|
+
* Returns an empty string when `coalition` is null/undefined or has no voting
|
|
212
|
+
* blocs.
|
|
213
|
+
*
|
|
214
|
+
* @param coalition - Coalition metrics data
|
|
215
|
+
* @param panelIndex - Index used for unique canvas IDs
|
|
216
|
+
* @param lang - BCP 47 language code for localized labels
|
|
217
|
+
* @returns HTML string for the coalition panel or empty string
|
|
218
|
+
*/
|
|
219
|
+
export function buildCoalitionPanel(coalition, panelIndex, lang = 'en') {
|
|
220
|
+
if (!coalition || coalition.votingBlocs.length === 0)
|
|
221
|
+
return '';
|
|
222
|
+
const d = getLocalizedString(DASHBOARD_BUILDER_STRINGS, lang);
|
|
223
|
+
const shiftLabel = coalition.shiftIndicator === 'strengthening'
|
|
224
|
+
? d.coalitionStrengthening
|
|
225
|
+
: coalition.shiftIndicator === 'weakening'
|
|
226
|
+
? d.coalitionWeakening
|
|
227
|
+
: d.coalitionStable;
|
|
228
|
+
const alignmentPct = `${coalition.alignmentScore}%`;
|
|
229
|
+
const shiftClass = coalitionShiftClass(coalition.shiftIndicator);
|
|
230
|
+
const radarChart = {
|
|
231
|
+
type: 'radar',
|
|
232
|
+
title: d.coalitionRadarChart,
|
|
233
|
+
data: {
|
|
234
|
+
labels: coalition.votingBlocs.map((b) => b.group),
|
|
235
|
+
datasets: [
|
|
236
|
+
{
|
|
237
|
+
label: d.alignmentScore,
|
|
238
|
+
data: coalition.votingBlocs.map((b) => b.alignmentScore),
|
|
239
|
+
backgroundColor: 'rgba(0,51,153,0.2)',
|
|
240
|
+
borderColor: '#003399',
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
const canvasId = `coalition-chart-${panelIndex}`;
|
|
246
|
+
const safeConfig = escapeHTML(JSON.stringify(radarChart));
|
|
247
|
+
const noscriptRows = coalition.votingBlocs
|
|
248
|
+
.map((b) => `<tr><th scope="row">${escapeHTML(b.group)}</th><td>${escapeHTML(String(b.alignmentScore))}%</td></tr>`)
|
|
249
|
+
.join('\n ');
|
|
250
|
+
return `<div class="dashboard-panel coalition-panel" role="region" aria-label="${escapeHTML(d.coalitionAlignment)}">
|
|
251
|
+
<h3 class="panel-title">${escapeHTML(d.coalitionAlignment)}</h3>
|
|
252
|
+
<div class="metrics-grid">
|
|
253
|
+
<div class="metric-card">
|
|
254
|
+
<span class="metric-label">${escapeHTML(d.alignmentScore)}</span>
|
|
255
|
+
<span class="metric-value">${escapeHTML(alignmentPct)}</span>
|
|
256
|
+
</div>
|
|
257
|
+
<div class="metric-card">
|
|
258
|
+
<span class="metric-label">${escapeHTML(d.votingBlocs)}</span>
|
|
259
|
+
<span class="metric-value">${escapeHTML(String(coalition.votingBlocs.length))}</span>
|
|
260
|
+
</div>
|
|
261
|
+
<div class="metric-card coalition-shift ${escapeHTML(shiftClass)}">
|
|
262
|
+
<span class="metric-label">${escapeHTML(d.coalitionShift)}</span>
|
|
263
|
+
<span class="metric-value">${escapeHTML(shiftLabel)}</span>
|
|
264
|
+
</div>
|
|
265
|
+
</div>
|
|
266
|
+
<div class="chart-container">
|
|
267
|
+
<h4 class="chart-title">${escapeHTML(d.coalitionRadarChart)}</h4>
|
|
268
|
+
<canvas id="${canvasId}" class="dashboard-chart" data-chart-config="${safeConfig}" role="img" aria-label="${escapeHTML(d.coalitionRadarChart)}"></canvas>
|
|
269
|
+
<noscript>
|
|
270
|
+
<table class="chart-fallback-table" role="table">
|
|
271
|
+
<thead><tr><th scope="col">${escapeHTML(d.votingBlocs)}</th><th scope="col">${escapeHTML(d.alignmentScore)}</th></tr></thead>
|
|
272
|
+
<tbody>
|
|
273
|
+
${noscriptRows}
|
|
274
|
+
</tbody>
|
|
275
|
+
</table>
|
|
276
|
+
</noscript>
|
|
277
|
+
</div>
|
|
278
|
+
</div>`;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Map a pipeline health score to its CSS status class.
|
|
282
|
+
*
|
|
283
|
+
* @param healthScore - Health score 0–100
|
|
284
|
+
* @returns CSS class string
|
|
285
|
+
*/
|
|
286
|
+
function pipelineStatusClass(healthScore) {
|
|
287
|
+
if (healthScore >= 70)
|
|
288
|
+
return 'pipeline-healthy';
|
|
289
|
+
if (healthScore >= 40)
|
|
290
|
+
return 'pipeline-moderate';
|
|
291
|
+
return 'pipeline-critical';
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Build a legislative pipeline status panel as a self-contained HTML section.
|
|
295
|
+
* Renders a horizontal bar chart (Chart.js) for on-track / delayed / blocked /
|
|
296
|
+
* fast-tracked counts with color-coded status classes and a `<noscript>`
|
|
297
|
+
* fallback list.
|
|
298
|
+
*
|
|
299
|
+
* Returns an empty string when `pipeline` is null/undefined or has zero total
|
|
300
|
+
* procedures.
|
|
301
|
+
*
|
|
302
|
+
* @param pipeline - Legislative pipeline data
|
|
303
|
+
* @param panelIndex - Index used for unique canvas IDs
|
|
304
|
+
* @param lang - BCP 47 language code for localized labels
|
|
305
|
+
* @returns HTML string for the pipeline panel or empty string
|
|
306
|
+
*/
|
|
307
|
+
export function buildPipelinePanel(pipeline, panelIndex, lang = 'en') {
|
|
308
|
+
if (!pipeline || pipeline.total === 0)
|
|
309
|
+
return '';
|
|
310
|
+
const d = getLocalizedString(DASHBOARD_BUILDER_STRINGS, lang);
|
|
311
|
+
const healthPct = `${pipeline.healthScore}%`;
|
|
312
|
+
const statusClass = pipelineStatusClass(pipeline.healthScore);
|
|
313
|
+
const barChart = {
|
|
314
|
+
type: 'bar',
|
|
315
|
+
title: d.pipelineStatusChart,
|
|
316
|
+
data: {
|
|
317
|
+
labels: [d.onTrack, d.delayed, d.blocked, d.fastTracked],
|
|
318
|
+
datasets: [
|
|
319
|
+
{
|
|
320
|
+
label: d.procedures,
|
|
321
|
+
data: [pipeline.onTrack, pipeline.delayed, pipeline.blocked, pipeline.fastTracked],
|
|
322
|
+
backgroundColor: ['#28a745', '#ffc107', '#dc3545', '#007bff'],
|
|
323
|
+
},
|
|
324
|
+
],
|
|
325
|
+
},
|
|
326
|
+
options: {
|
|
327
|
+
indexAxis: 'y',
|
|
328
|
+
},
|
|
329
|
+
};
|
|
330
|
+
const canvasId = `pipeline-chart-${panelIndex}`;
|
|
331
|
+
const safeConfig = escapeHTML(JSON.stringify(barChart));
|
|
332
|
+
return `<div class="dashboard-panel pipeline-panel ${escapeHTML(statusClass)}" role="region" aria-label="${escapeHTML(d.pipelineStatus)}">
|
|
333
|
+
<h3 class="panel-title">${escapeHTML(d.pipelineStatus)}</h3>
|
|
334
|
+
<div class="metrics-grid">
|
|
335
|
+
<div class="metric-card pipeline-on-track">
|
|
336
|
+
<span class="metric-label">${escapeHTML(d.onTrack)}</span>
|
|
337
|
+
<span class="metric-value">${escapeHTML(String(pipeline.onTrack))}</span>
|
|
338
|
+
</div>
|
|
339
|
+
<div class="metric-card pipeline-delayed">
|
|
340
|
+
<span class="metric-label">${escapeHTML(d.delayed)}</span>
|
|
341
|
+
<span class="metric-value">${escapeHTML(String(pipeline.delayed))}</span>
|
|
342
|
+
</div>
|
|
343
|
+
<div class="metric-card pipeline-blocked">
|
|
344
|
+
<span class="metric-label">${escapeHTML(d.blocked)}</span>
|
|
345
|
+
<span class="metric-value">${escapeHTML(String(pipeline.blocked))}</span>
|
|
346
|
+
</div>
|
|
347
|
+
<div class="metric-card pipeline-fast-tracked">
|
|
348
|
+
<span class="metric-label">${escapeHTML(d.fastTracked)}</span>
|
|
349
|
+
<span class="metric-value">${escapeHTML(String(pipeline.fastTracked))}</span>
|
|
350
|
+
</div>
|
|
351
|
+
</div>
|
|
352
|
+
<div class="pipeline-health-indicator ${escapeHTML(statusClass)}">
|
|
353
|
+
<span class="metric-label">${escapeHTML(d.healthScore)}</span>
|
|
354
|
+
<span class="metric-value">${escapeHTML(healthPct)}</span>
|
|
355
|
+
</div>
|
|
356
|
+
<div class="chart-container">
|
|
357
|
+
<h4 class="chart-title">${escapeHTML(d.pipelineStatusChart)}</h4>
|
|
358
|
+
<canvas id="${canvasId}" class="dashboard-chart" data-chart-config="${safeConfig}" role="img" aria-label="${escapeHTML(d.pipelineStatusChart)}"></canvas>
|
|
359
|
+
<noscript>
|
|
360
|
+
<ul class="pipeline-fallback-list">
|
|
361
|
+
<li>${escapeHTML(d.onTrack)}: ${escapeHTML(String(pipeline.onTrack))}</li>
|
|
362
|
+
<li>${escapeHTML(d.delayed)}: ${escapeHTML(String(pipeline.delayed))}</li>
|
|
363
|
+
<li>${escapeHTML(d.blocked)}: ${escapeHTML(String(pipeline.blocked))}</li>
|
|
364
|
+
<li>${escapeHTML(d.fastTracked)}: ${escapeHTML(String(pipeline.fastTracked))}</li>
|
|
365
|
+
</ul>
|
|
366
|
+
</noscript>
|
|
367
|
+
</div>
|
|
368
|
+
</div>`;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Build a trend analytics panel as a self-contained HTML section.
|
|
372
|
+
* Renders a line (sparkline) chart (Chart.js) for activity levels over time
|
|
373
|
+
* with week-over-week / month-over-month change indicators and a `<noscript>`
|
|
374
|
+
* comparison table.
|
|
375
|
+
*
|
|
376
|
+
* Returns an empty string when `trend` is null/undefined or has no metric
|
|
377
|
+
* data points.
|
|
378
|
+
*
|
|
379
|
+
* @param trend - Trend analytics data
|
|
380
|
+
* @param panelIndex - Index used for unique canvas IDs
|
|
381
|
+
* @param lang - BCP 47 language code for localized labels
|
|
382
|
+
* @returns HTML string for the trend panel or empty string
|
|
383
|
+
*/
|
|
384
|
+
export function buildTrendPanel(trend, panelIndex, lang = 'en') {
|
|
385
|
+
if (!trend || trend.metrics.length === 0)
|
|
386
|
+
return '';
|
|
387
|
+
const d = getLocalizedString(DASHBOARD_BUILDER_STRINGS, lang);
|
|
388
|
+
const directionLabel = trend.direction === 'improving'
|
|
389
|
+
? d.trendImproving
|
|
390
|
+
: trend.direction === 'declining'
|
|
391
|
+
? d.trendDeclining
|
|
392
|
+
: d.trendStableLabel;
|
|
393
|
+
const sparklineChart = {
|
|
394
|
+
type: 'line',
|
|
395
|
+
title: d.activityTrendChart,
|
|
396
|
+
data: {
|
|
397
|
+
labels: trend.metrics.map((m) => m.period),
|
|
398
|
+
datasets: [
|
|
399
|
+
{
|
|
400
|
+
label: d.trendAnalysis,
|
|
401
|
+
data: trend.metrics.map((m) => m.value),
|
|
402
|
+
borderColor: '#003399',
|
|
403
|
+
backgroundColor: 'rgba(0,51,153,0.1)',
|
|
404
|
+
},
|
|
405
|
+
],
|
|
406
|
+
},
|
|
407
|
+
options: {
|
|
408
|
+
plugins: { legend: { display: false } },
|
|
409
|
+
scales: { y: { beginAtZero: true } },
|
|
410
|
+
},
|
|
411
|
+
};
|
|
412
|
+
const canvasId = `trend-chart-${panelIndex}`;
|
|
413
|
+
const safeConfig = escapeHTML(JSON.stringify(sparklineChart));
|
|
414
|
+
const wowHtml = trend.weekOverWeekChange !== undefined
|
|
415
|
+
? `<div class="metric-card">
|
|
416
|
+
<span class="metric-label">${escapeHTML(d.weekOverWeek)}</span>
|
|
417
|
+
<span class="metric-value">${escapeHTML(trend.weekOverWeekChange > 0 ? '+' : '')}${escapeHTML(String(trend.weekOverWeekChange))}%</span>
|
|
418
|
+
</div>`
|
|
419
|
+
: '';
|
|
420
|
+
const momHtml = trend.monthOverMonthChange !== undefined
|
|
421
|
+
? `<div class="metric-card">
|
|
422
|
+
<span class="metric-label">${escapeHTML(d.monthOverMonth)}</span>
|
|
423
|
+
<span class="metric-value">${escapeHTML(trend.monthOverMonthChange > 0 ? '+' : '')}${escapeHTML(String(trend.monthOverMonthChange))}%</span>
|
|
424
|
+
</div>`
|
|
425
|
+
: '';
|
|
426
|
+
const noscriptRows = trend.metrics
|
|
427
|
+
.map((m) => `<tr><th scope="row">${escapeHTML(m.period)}</th><td>${escapeHTML(String(m.value))}</td></tr>`)
|
|
428
|
+
.join('\n ');
|
|
429
|
+
return `<div class="dashboard-panel trend-panel" role="region" aria-label="${escapeHTML(d.trendAnalysis)}">
|
|
430
|
+
<h3 class="panel-title">${escapeHTML(d.trendAnalysis)}</h3>
|
|
431
|
+
<div class="metrics-grid">
|
|
432
|
+
<div class="metric-card trend-direction">
|
|
433
|
+
<span class="metric-label">${escapeHTML(d.trendAnalysis)}</span>
|
|
434
|
+
<span class="metric-value">${escapeHTML(directionLabel)}</span>
|
|
435
|
+
</div>
|
|
436
|
+
${wowHtml}
|
|
437
|
+
${momHtml}
|
|
438
|
+
</div>
|
|
439
|
+
<div class="chart-container">
|
|
440
|
+
<h4 class="chart-title">${escapeHTML(d.activityTrendChart)}</h4>
|
|
441
|
+
<canvas id="${canvasId}" class="dashboard-chart" data-chart-config="${safeConfig}" role="img" aria-label="${escapeHTML(d.activityTrendChart)}"></canvas>
|
|
442
|
+
<noscript>
|
|
443
|
+
<table class="chart-fallback-table" role="table">
|
|
444
|
+
<thead><tr><th scope="col">${escapeHTML(d.trendAnalysis)}</th><th scope="col">${escapeHTML(d.status)}</th></tr></thead>
|
|
445
|
+
<tbody>
|
|
446
|
+
${noscriptRows}
|
|
447
|
+
</tbody>
|
|
448
|
+
</table>
|
|
449
|
+
</noscript>
|
|
450
|
+
</div>
|
|
451
|
+
</div>`;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Map an impact direction to its CSS class for color-coded scorecards.
|
|
455
|
+
*
|
|
456
|
+
* @param direction - Impact direction
|
|
457
|
+
* @returns CSS class string
|
|
458
|
+
*/
|
|
459
|
+
function impactDirectionClass(direction) {
|
|
460
|
+
switch (direction) {
|
|
461
|
+
case 'positive':
|
|
462
|
+
return 'impact-positive';
|
|
463
|
+
case 'negative':
|
|
464
|
+
return 'impact-negative';
|
|
465
|
+
case 'neutral':
|
|
466
|
+
return 'impact-neutral';
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Build a stakeholder impact scorecard panel as a self-contained HTML section.
|
|
471
|
+
* Renders a color-coded grid where each cell shows a stakeholder's impact score
|
|
472
|
+
* and direction, with a `<noscript>` fallback table.
|
|
473
|
+
*
|
|
474
|
+
* Returns an empty string when `stakeholders` is null/undefined or empty.
|
|
475
|
+
*
|
|
476
|
+
* @param stakeholders - Stakeholder metric data
|
|
477
|
+
* @param panelIndex - Index used for unique IDs
|
|
478
|
+
* @param lang - BCP 47 language code for localized labels
|
|
479
|
+
* @returns HTML string for the scorecard panel or empty string
|
|
480
|
+
*/
|
|
481
|
+
export function buildStakeholderScorecardPanel(stakeholders, panelIndex, lang = 'en') {
|
|
482
|
+
if (!stakeholders || stakeholders.length === 0)
|
|
483
|
+
return '';
|
|
484
|
+
const d = getLocalizedString(DASHBOARD_BUILDER_STRINGS, lang);
|
|
485
|
+
const cards = stakeholders
|
|
486
|
+
.map((s) => {
|
|
487
|
+
const dirClass = impactDirectionClass(s.impactDirection);
|
|
488
|
+
const dirLabel = s.impactDirection === 'positive'
|
|
489
|
+
? d.impactPositive
|
|
490
|
+
: s.impactDirection === 'negative'
|
|
491
|
+
? d.impactNegative
|
|
492
|
+
: d.impactNeutral;
|
|
493
|
+
const descHtml = s.description
|
|
494
|
+
? `<span class="stakeholder-description">${escapeHTML(s.description)}</span>`
|
|
495
|
+
: '';
|
|
496
|
+
return `<div class="stakeholder-card ${escapeHTML(dirClass)}" role="listitem">
|
|
497
|
+
<span class="stakeholder-name">${escapeHTML(s.stakeholder)}</span>
|
|
498
|
+
<span class="stakeholder-score">${escapeHTML(String(s.impactScore))}/100</span>
|
|
499
|
+
<span class="stakeholder-direction">${escapeHTML(dirLabel)}</span>
|
|
500
|
+
${descHtml}
|
|
501
|
+
</div>`;
|
|
502
|
+
})
|
|
503
|
+
.join('\n ');
|
|
504
|
+
const noscriptRows = stakeholders
|
|
505
|
+
.map((s) => {
|
|
506
|
+
const dirLabel = s.impactDirection === 'positive'
|
|
507
|
+
? d.impactPositive
|
|
508
|
+
: s.impactDirection === 'negative'
|
|
509
|
+
? d.impactNegative
|
|
510
|
+
: d.impactNeutral;
|
|
511
|
+
return `<tr><th scope="row">${escapeHTML(s.stakeholder)}</th><td>${escapeHTML(String(s.impactScore))}</td><td>${escapeHTML(dirLabel)}</td></tr>`;
|
|
512
|
+
})
|
|
513
|
+
.join('\n ');
|
|
514
|
+
return `<div class="dashboard-panel stakeholder-scorecard" role="region" aria-label="${escapeHTML(d.stakeholderImpact)}" id="stakeholder-scorecard-${panelIndex}">
|
|
515
|
+
<h3 class="panel-title">${escapeHTML(d.stakeholderImpact)}</h3>
|
|
516
|
+
<div class="stakeholder-grid" role="list">
|
|
517
|
+
${cards}
|
|
518
|
+
</div>
|
|
519
|
+
<noscript>
|
|
520
|
+
<table class="chart-fallback-table" role="table">
|
|
521
|
+
<thead><tr><th scope="col">${escapeHTML(d.stakeholderImpact)}</th><th scope="col">${escapeHTML(d.impactScore)}</th><th scope="col">${escapeHTML(d.status)}</th></tr></thead>
|
|
522
|
+
<tbody>
|
|
523
|
+
${noscriptRows}
|
|
524
|
+
</tbody>
|
|
525
|
+
</table>
|
|
526
|
+
</noscript>
|
|
527
|
+
</div>`;
|
|
528
|
+
}
|
|
529
|
+
// ─── Main builder ────────────────────────────────────────────────────────────
|
|
530
|
+
/**
|
|
531
|
+
* Build a complete dashboard section HTML.
|
|
532
|
+
*
|
|
533
|
+
* Generates an accessible dashboard with metric cards and chart containers.
|
|
534
|
+
* Charts are embedded as Canvas elements with `data-chart-config` JSON
|
|
535
|
+
* attributes for client-side Chart.js hydration. A `<noscript>` fallback
|
|
536
|
+
* provides accessible data tables when JavaScript is disabled.
|
|
537
|
+
*
|
|
538
|
+
* Returns an empty string if the config is null/undefined or contains
|
|
539
|
+
* no panels with content.
|
|
540
|
+
*
|
|
541
|
+
* @param config - Dashboard configuration (null/undefined returns empty string)
|
|
542
|
+
* @param lang - BCP 47 language code for localized UI text (defaults to "en")
|
|
543
|
+
* @param heading - Optional custom section heading override
|
|
544
|
+
* @returns HTML section string or empty string
|
|
545
|
+
*/
|
|
546
|
+
export function buildDashboardSection(config, lang = 'en', heading) {
|
|
547
|
+
if (!config)
|
|
548
|
+
return '';
|
|
549
|
+
if (config.panels.length === 0)
|
|
550
|
+
return '';
|
|
551
|
+
const strings = getLocalizedString(DASHBOARD_STRINGS, lang);
|
|
552
|
+
const sectionHeading = heading ?? config.title ?? strings.sectionHeading;
|
|
553
|
+
const panelsHtml = config.panels
|
|
554
|
+
.map((panel, index) => buildDashboardPanel(panel, index, strings))
|
|
555
|
+
.filter((html) => html.length > 0)
|
|
556
|
+
.join('\n ');
|
|
557
|
+
if (!panelsHtml)
|
|
558
|
+
return '';
|
|
559
|
+
return `
|
|
560
|
+
<section class="dashboard" role="region" aria-label="${escapeHTML(sectionHeading)}">
|
|
561
|
+
<h2>${escapeHTML(sectionHeading)}</h2>
|
|
562
|
+
<div class="dashboard-grid">
|
|
563
|
+
${panelsHtml}
|
|
564
|
+
</div>
|
|
565
|
+
</section>`;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Check whether a dashboard configuration contains any chart containers.
|
|
569
|
+
* Useful for conditionally including Chart.js client-side scripts.
|
|
570
|
+
*
|
|
571
|
+
* @param config - Dashboard configuration
|
|
572
|
+
* @returns True if at least one panel has a chart
|
|
573
|
+
*/
|
|
574
|
+
export function dashboardHasCharts(config) {
|
|
575
|
+
if (!config)
|
|
576
|
+
return false;
|
|
577
|
+
return config.panels.some((panel) => panel.chart !== undefined);
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Build a dashboard panel from World Bank economic context data.
|
|
581
|
+
*
|
|
582
|
+
* Generates a bar chart showing key economic indicators for a country
|
|
583
|
+
* alongside metric cards for each indicator, enriching articles with
|
|
584
|
+
* macroeconomic context relevant to EU Parliament policy analysis.
|
|
585
|
+
*
|
|
586
|
+
* @param context - Economic context data from World Bank MCP
|
|
587
|
+
* @returns Dashboard panel configuration or null if data is insufficient
|
|
588
|
+
*/
|
|
589
|
+
export function buildEconomicContextPanel(context) {
|
|
590
|
+
if (!context?.indicators || context.indicators.length === 0)
|
|
591
|
+
return null;
|
|
592
|
+
const validIndicators = context.indicators.filter((ind) => ind.value !== null && ind.value !== undefined && Number.isFinite(ind.value));
|
|
593
|
+
if (validIndicators.length === 0)
|
|
594
|
+
return null;
|
|
595
|
+
const metrics = validIndicators.slice(0, 6).map((ind) => {
|
|
596
|
+
const labelYearSuffix = ind.year !== undefined && ind.year !== null ? ` (${ind.year})` : '';
|
|
597
|
+
return {
|
|
598
|
+
label: `${ind.name}${labelYearSuffix}`,
|
|
599
|
+
value: ind.formatted,
|
|
600
|
+
unit: '',
|
|
601
|
+
};
|
|
602
|
+
});
|
|
603
|
+
// Only chart indicators with comparable units (percentages) to avoid
|
|
604
|
+
// mixing incompatible scales (e.g. GDP in $ alongside inflation in %).
|
|
605
|
+
// Percentage indicators (growth rates, inflation, unemployment) share a
|
|
606
|
+
// common axis; absolute-value indicators still appear in the metrics cards.
|
|
607
|
+
const pctIndicators = validIndicators.filter((ind) => ind.formatted.includes('%'));
|
|
608
|
+
const chartIndicators = pctIndicators.length > 0 ? pctIndicators.slice(0, 6) : [];
|
|
609
|
+
const chart = chartIndicators.length > 0
|
|
610
|
+
? {
|
|
611
|
+
type: 'bar',
|
|
612
|
+
title: `${context.countryName} — Economic Rates (%)`,
|
|
613
|
+
data: {
|
|
614
|
+
labels: chartIndicators.map((ind) => ind.name),
|
|
615
|
+
datasets: [
|
|
616
|
+
{
|
|
617
|
+
label: context.countryName,
|
|
618
|
+
data: chartIndicators.map((ind) => ind.value ?? 0),
|
|
619
|
+
},
|
|
620
|
+
],
|
|
621
|
+
},
|
|
622
|
+
}
|
|
623
|
+
: undefined;
|
|
624
|
+
return {
|
|
625
|
+
title: `Economic Context: ${context.countryName}`,
|
|
626
|
+
metrics,
|
|
627
|
+
...(chart ? { chart } : {}),
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
//# sourceMappingURL=dashboard-content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-content.js","sourceRoot":"","sources":["../../src/generators/dashboard-content.ts"],"names":[],"mappings":"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"}
|