@planu/cli 0.54.2 → 0.56.0
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/dist/config/license-plans.json +1 -0
- package/dist/engine/doc-generator/executive-summary/executive-summary-generator.d.ts +7 -1
- package/dist/engine/doc-generator/executive-summary/executive-summary-generator.d.ts.map +1 -1
- package/dist/engine/doc-generator/executive-summary/executive-summary-generator.js +16 -3
- package/dist/engine/doc-generator/executive-summary/executive-summary-generator.js.map +1 -1
- package/dist/engine/doc-generator/executive-summary/html-template.d.ts +5 -2
- package/dist/engine/doc-generator/executive-summary/html-template.d.ts.map +1 -1
- package/dist/engine/doc-generator/executive-summary/html-template.js +7 -3
- package/dist/engine/doc-generator/executive-summary/html-template.js.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/executive-report.d.ts +3 -1
- package/dist/engine/doc-generator/per-spec-report/executive-report.d.ts.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/executive-report.js +22 -2
- package/dist/engine/doc-generator/per-spec-report/executive-report.js.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/html-wrapper.d.ts +5 -3
- package/dist/engine/doc-generator/per-spec-report/html-wrapper.d.ts.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/html-wrapper.js +27 -6
- package/dist/engine/doc-generator/per-spec-report/html-wrapper.js.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.d.ts +1 -0
- package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.d.ts.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.js +29 -0
- package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.js.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/spec-section-builders.d.ts +8 -1
- package/dist/engine/doc-generator/per-spec-report/spec-section-builders.d.ts.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/spec-section-builders.js +188 -0
- package/dist/engine/doc-generator/per-spec-report/spec-section-builders.js.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/technical-report.d.ts +3 -1
- package/dist/engine/doc-generator/per-spec-report/technical-report.d.ts.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/technical-report.js +24 -7
- package/dist/engine/doc-generator/per-spec-report/technical-report.js.map +1 -1
- package/dist/engine/doc-generator/portal/analytics-page.d.ts +8 -0
- package/dist/engine/doc-generator/portal/analytics-page.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/analytics-page.js +265 -0
- package/dist/engine/doc-generator/portal/analytics-page.js.map +1 -0
- package/dist/engine/doc-generator/portal/architecture-page.d.ts +6 -0
- package/dist/engine/doc-generator/portal/architecture-page.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/architecture-page.js +250 -0
- package/dist/engine/doc-generator/portal/architecture-page.js.map +1 -0
- package/dist/engine/doc-generator/portal/changelog-page.d.ts +6 -0
- package/dist/engine/doc-generator/portal/changelog-page.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/changelog-page.js +204 -0
- package/dist/engine/doc-generator/portal/changelog-page.js.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.d.ts +11 -0
- package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.js +24 -0
- package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.js.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.d.ts +9 -0
- package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.js +31 -0
- package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.js.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.d.ts +10 -0
- package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.js +77 -0
- package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.js.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.d.ts +9 -0
- package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.js +31 -0
- package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.js.map +1 -0
- package/dist/engine/doc-generator/portal/decision-page.d.ts +6 -0
- package/dist/engine/doc-generator/portal/decision-page.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/decision-page.js +169 -0
- package/dist/engine/doc-generator/portal/decision-page.js.map +1 -0
- package/dist/engine/doc-generator/portal/decision-timeline-builder.d.ts +8 -0
- package/dist/engine/doc-generator/portal/decision-timeline-builder.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/decision-timeline-builder.js +131 -0
- package/dist/engine/doc-generator/portal/decision-timeline-builder.js.map +1 -0
- package/dist/engine/doc-generator/portal/index.d.ts +19 -0
- package/dist/engine/doc-generator/portal/index.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/index.js +21 -0
- package/dist/engine/doc-generator/portal/index.js.map +1 -0
- package/dist/engine/doc-generator/portal/kanban-view-builder.d.ts +8 -0
- package/dist/engine/doc-generator/portal/kanban-view-builder.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/kanban-view-builder.js +140 -0
- package/dist/engine/doc-generator/portal/kanban-view-builder.js.map +1 -0
- package/dist/engine/doc-generator/portal/portal-breadcrumbs.d.ts +27 -0
- package/dist/engine/doc-generator/portal/portal-breadcrumbs.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/portal-breadcrumbs.js +139 -0
- package/dist/engine/doc-generator/portal/portal-breadcrumbs.js.map +1 -0
- package/dist/engine/doc-generator/portal/portal-landing-cards.d.ts +8 -0
- package/dist/engine/doc-generator/portal/portal-landing-cards.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/portal-landing-cards.js +177 -0
- package/dist/engine/doc-generator/portal/portal-landing-cards.js.map +1 -0
- package/dist/engine/doc-generator/portal/portal-navbar.d.ts +15 -0
- package/dist/engine/doc-generator/portal/portal-navbar.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/portal-navbar.js +143 -0
- package/dist/engine/doc-generator/portal/portal-navbar.js.map +1 -0
- package/dist/engine/doc-generator/portal/portal-page-detector.d.ts +22 -0
- package/dist/engine/doc-generator/portal/portal-page-detector.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/portal-page-detector.js +58 -0
- package/dist/engine/doc-generator/portal/portal-page-detector.js.map +1 -0
- package/dist/engine/doc-generator/portal/portal-theme.d.ts +7 -0
- package/dist/engine/doc-generator/portal/portal-theme.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/portal-theme.js +53 -0
- package/dist/engine/doc-generator/portal/portal-theme.js.map +1 -0
- package/dist/engine/doc-generator/portal/risk-gauge-svg.d.ts +5 -0
- package/dist/engine/doc-generator/portal/risk-gauge-svg.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/risk-gauge-svg.js +80 -0
- package/dist/engine/doc-generator/portal/risk-gauge-svg.js.map +1 -0
- package/dist/engine/doc-generator/portal/risk-matrix-svg.d.ts +11 -0
- package/dist/engine/doc-generator/portal/risk-matrix-svg.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/risk-matrix-svg.js +181 -0
- package/dist/engine/doc-generator/portal/risk-matrix-svg.js.map +1 -0
- package/dist/engine/doc-generator/portal/risk-page.d.ts +7 -0
- package/dist/engine/doc-generator/portal/risk-page.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/risk-page.js +219 -0
- package/dist/engine/doc-generator/portal/risk-page.js.map +1 -0
- package/dist/engine/doc-generator/portal/roadmap-page.d.ts +7 -0
- package/dist/engine/doc-generator/portal/roadmap-page.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/roadmap-page.js +204 -0
- package/dist/engine/doc-generator/portal/roadmap-page.js.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/bar-chart.d.ts +4 -0
- package/dist/engine/doc-generator/portal/svg-charts/bar-chart.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/bar-chart.js +50 -0
- package/dist/engine/doc-generator/portal/svg-charts/bar-chart.js.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/chart-utils.d.ts +16 -0
- package/dist/engine/doc-generator/portal/svg-charts/chart-utils.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/chart-utils.js +45 -0
- package/dist/engine/doc-generator/portal/svg-charts/chart-utils.js.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/line-chart.d.ts +16 -0
- package/dist/engine/doc-generator/portal/svg-charts/line-chart.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/line-chart.js +159 -0
- package/dist/engine/doc-generator/portal/svg-charts/line-chart.js.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/pie-chart.d.ts +7 -0
- package/dist/engine/doc-generator/portal/svg-charts/pie-chart.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/pie-chart.js +52 -0
- package/dist/engine/doc-generator/portal/svg-charts/pie-chart.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-gantt-builder.d.ts +8 -0
- package/dist/engine/doc-generator/proposal/proposal-gantt-builder.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-gantt-builder.js +126 -0
- package/dist/engine/doc-generator/proposal/proposal-gantt-builder.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-generator.d.ts +10 -0
- package/dist/engine/doc-generator/proposal/proposal-generator.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-generator.js +93 -0
- package/dist/engine/doc-generator/proposal/proposal-generator.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-html-wrapper.d.ts +7 -0
- package/dist/engine/doc-generator/proposal/proposal-html-wrapper.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-html-wrapper.js +31 -0
- package/dist/engine/doc-generator/proposal/proposal-html-wrapper.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-i18n.d.ts +12 -0
- package/dist/engine/doc-generator/proposal/proposal-i18n.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-i18n.js +230 -0
- package/dist/engine/doc-generator/proposal/proposal-i18n.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-kpi-builder.d.ts +8 -0
- package/dist/engine/doc-generator/proposal/proposal-kpi-builder.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-kpi-builder.js +32 -0
- package/dist/engine/doc-generator/proposal/proposal-kpi-builder.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.d.ts +14 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.js +248 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders.d.ts +13 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders.js +423 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-themes.d.ts +4 -0
- package/dist/engine/doc-generator/proposal/proposal-themes.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-themes.js +194 -0
- package/dist/engine/doc-generator/proposal/proposal-themes.js.map +1 -0
- package/dist/engine/spec-summary-html.d.ts.map +1 -1
- package/dist/engine/spec-summary-html.js +17 -5
- package/dist/engine/spec-summary-html.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/generate-proposal.d.ts +3 -0
- package/dist/tools/generate-proposal.d.ts.map +1 -0
- package/dist/tools/generate-proposal.js +166 -0
- package/dist/tools/generate-proposal.js.map +1 -0
- package/dist/types/docs.d.ts +75 -0
- package/dist/types/docs.d.ts.map +1 -1
- package/dist/types/portal.d.ts +128 -0
- package/dist/types/portal.d.ts.map +1 -0
- package/dist/types/portal.js +3 -0
- package/dist/types/portal.js.map +1 -0
- package/dist/types/proposal.d.ts +57 -0
- package/dist/types/proposal.d.ts.map +1 -0
- package/dist/types/proposal.js +2 -0
- package/dist/types/proposal.js.map +1 -0
- package/package.json +1 -1
- package/src/config/license-plans.json +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portal-theme.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/portal/portal-theme.ts"],"names":[],"mappings":"AAAA,yEAAyE;AAEzE;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2CL,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk-gauge-svg.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/portal/risk-gauge-svg.ts"],"names":[],"mappings":"AAkDA;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAwCvD"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Planu — Risk Gauge semicircle SVG (SPEC-143)
|
|
2
|
+
const W = 200;
|
|
3
|
+
const H = 120;
|
|
4
|
+
const CX = W / 2;
|
|
5
|
+
const CY = 105;
|
|
6
|
+
const R = 80;
|
|
7
|
+
/**
|
|
8
|
+
* Convert polar angle (in degrees, 0 = right) to SVG x,y on the gauge arc.
|
|
9
|
+
* Gauge goes from 180° (left) to 0° (right), i.e. the top semicircle.
|
|
10
|
+
*/
|
|
11
|
+
function polarToXY(angleDeg, radius) {
|
|
12
|
+
const rad = (angleDeg * Math.PI) / 180;
|
|
13
|
+
return {
|
|
14
|
+
x: CX + radius * Math.cos(rad),
|
|
15
|
+
y: CY - radius * Math.sin(rad),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function scoreToAngle(score) {
|
|
19
|
+
// Map 0→180°, 100→0° (left to right)
|
|
20
|
+
const clamped = Math.max(0, Math.min(100, score));
|
|
21
|
+
return 180 - clamped * 1.8;
|
|
22
|
+
}
|
|
23
|
+
function gaugeColor(score) {
|
|
24
|
+
if (score <= 30) {
|
|
25
|
+
return '#22c55e';
|
|
26
|
+
} // green
|
|
27
|
+
if (score <= 60) {
|
|
28
|
+
return '#f59e0b';
|
|
29
|
+
} // yellow
|
|
30
|
+
return '#ef4444'; // red
|
|
31
|
+
}
|
|
32
|
+
function buildArcPath(startAngle, endAngle, r, _strokeWidth) {
|
|
33
|
+
const start = polarToXY(startAngle, r);
|
|
34
|
+
const end = polarToXY(endAngle, r);
|
|
35
|
+
const largeArc = Math.abs(endAngle - startAngle) > 180 ? 1 : 0;
|
|
36
|
+
// Sweep: going from high angle to low angle means clockwise in SVG
|
|
37
|
+
const sweep = endAngle < startAngle ? 1 : 0;
|
|
38
|
+
return `M ${start.x.toFixed(1)} ${start.y.toFixed(1)} A ${r} ${r} 0 ${largeArc} ${sweep} ${end.x.toFixed(1)} ${end.y.toFixed(1)}`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Build a semicircle gauge SVG for a risk score (0-100).
|
|
42
|
+
*/
|
|
43
|
+
export function buildRiskGaugeSvg(score) {
|
|
44
|
+
const clamped = Math.max(0, Math.min(100, score));
|
|
45
|
+
const color = gaugeColor(clamped);
|
|
46
|
+
const needleAngle = scoreToAngle(clamped);
|
|
47
|
+
const needle = polarToXY(needleAngle, R - 10);
|
|
48
|
+
// Background arc (grey, full 180°)
|
|
49
|
+
const bgPath = buildArcPath(180, 0, R, 14);
|
|
50
|
+
// Foreground arc (colored, proportional)
|
|
51
|
+
const fgPath = buildArcPath(180, needleAngle, R, 14);
|
|
52
|
+
// Zone arcs (thin overlay for green/yellow/red zones)
|
|
53
|
+
const greenEnd = scoreToAngle(30);
|
|
54
|
+
const yellowEnd = scoreToAngle(60);
|
|
55
|
+
const greenArc = buildArcPath(180, greenEnd, R, 14);
|
|
56
|
+
const yellowArc = buildArcPath(greenEnd, yellowEnd, R, 14);
|
|
57
|
+
const redArc = buildArcPath(yellowEnd, 0, R, 14);
|
|
58
|
+
return `<svg viewBox="0 0 ${W} ${H}" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Risk Score Gauge: ${clamped}">
|
|
59
|
+
<!-- Zone backgrounds -->
|
|
60
|
+
<path d="${greenArc}" fill="none" stroke="#d1fae5" stroke-width="14" stroke-linecap="butt"/>
|
|
61
|
+
<path d="${yellowArc}" fill="none" stroke="#fef3c7" stroke-width="14" stroke-linecap="butt"/>
|
|
62
|
+
<path d="${redArc}" fill="none" stroke="#fee2e2" stroke-width="14" stroke-linecap="butt"/>
|
|
63
|
+
<!-- Progress arc -->
|
|
64
|
+
<path d="${bgPath}" fill="none" stroke="#e5e7eb" stroke-width="10" stroke-linecap="round"/>
|
|
65
|
+
<path d="${fgPath}" fill="none" stroke="${color}" stroke-width="10" stroke-linecap="round"/>
|
|
66
|
+
<!-- Needle dot -->
|
|
67
|
+
<circle cx="${needle.x.toFixed(1)}" cy="${needle.y.toFixed(1)}" r="5" fill="${color}" stroke="white" stroke-width="2"/>
|
|
68
|
+
<!-- Center dot -->
|
|
69
|
+
<circle cx="${CX}" cy="${CY}" r="4" fill="#374151"/>
|
|
70
|
+
<!-- Score number -->
|
|
71
|
+
<text x="${CX}" y="${CY - 20}" text-anchor="middle" font-size="28" font-weight="700" fill="${color}">${clamped}</text>
|
|
72
|
+
<!-- Label -->
|
|
73
|
+
<text x="${CX}" y="${CY - 4}" text-anchor="middle" font-size="11" fill="#6b7280">Risk Score</text>
|
|
74
|
+
<!-- Scale labels -->
|
|
75
|
+
<text x="14" y="${CY + 16}" font-size="9" fill="#6b7280">0</text>
|
|
76
|
+
<text x="${CX - 4}" y="22" font-size="9" fill="#6b7280">50</text>
|
|
77
|
+
<text x="${W - 22}" y="${CY + 16}" font-size="9" fill="#6b7280">100</text>
|
|
78
|
+
</svg>`;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=risk-gauge-svg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk-gauge-svg.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/portal/risk-gauge-svg.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SpecRisk, RiskCategory } from '../../../types/risk.js';
|
|
2
|
+
declare const IMPACT_LEVELS: readonly ["low", "medium", "high", "very_high", "critical"];
|
|
3
|
+
declare const PROB_LEVELS: readonly [20, 40, 60, 80, 100];
|
|
4
|
+
declare const CATEGORY_COLORS: Record<RiskCategory, string>;
|
|
5
|
+
/**
|
|
6
|
+
* Build a 5x5 risk matrix SVG.
|
|
7
|
+
* Returns empty string when risks array is empty.
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildRiskMatrixSvg(risks: SpecRisk[]): string;
|
|
10
|
+
export { IMPACT_LEVELS, PROB_LEVELS, CATEGORY_COLORS };
|
|
11
|
+
//# sourceMappingURL=risk-matrix-svg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk-matrix-svg.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/portal/risk-matrix-svg.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAErE,QAAA,MAAM,aAAa,6DAA8D,CAAC;AAClF,QAAA,MAAM,WAAW,gCAAiC,CAAC;AAEnD,QAAA,MAAM,eAAe,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAOjD,CAAC;AA2LF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAc5D;AAED,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
const IMPACT_LEVELS = ['low', 'medium', 'high', 'very_high', 'critical'];
|
|
2
|
+
const PROB_LEVELS = [20, 40, 60, 80, 100];
|
|
3
|
+
const CATEGORY_COLORS = {
|
|
4
|
+
technical: '#3b82f6',
|
|
5
|
+
security: '#ef4444',
|
|
6
|
+
integration: '#f97316',
|
|
7
|
+
dependency: '#8b5cf6',
|
|
8
|
+
organizational: '#6b7280',
|
|
9
|
+
data: '#10b981',
|
|
10
|
+
};
|
|
11
|
+
const QUADRANT_COLORS = [
|
|
12
|
+
// Row 0 (prob 80-100) high prob
|
|
13
|
+
['#fef3c7', '#fde68a', '#fcd34d', '#f87171', '#ef4444'],
|
|
14
|
+
// Row 1 (prob 60-80)
|
|
15
|
+
['#d1fae5', '#fef3c7', '#fde68a', '#fcd34d', '#f87171'],
|
|
16
|
+
// Row 2 (prob 40-60)
|
|
17
|
+
['#d1fae5', '#d1fae5', '#fef3c7', '#fde68a', '#fcd34d'],
|
|
18
|
+
// Row 3 (prob 20-40)
|
|
19
|
+
['#d1fae5', '#d1fae5', '#d1fae5', '#fef3c7', '#fde68a'],
|
|
20
|
+
// Row 4 (prob 0-20) low prob
|
|
21
|
+
['#d1fae5', '#d1fae5', '#d1fae5', '#d1fae5', '#fef3c7'],
|
|
22
|
+
];
|
|
23
|
+
const CELL = 60;
|
|
24
|
+
const PADDING = 40;
|
|
25
|
+
const LABEL_PAD = 14;
|
|
26
|
+
const GRID_W = CELL * 5;
|
|
27
|
+
const GRID_H = CELL * 5;
|
|
28
|
+
const SVG_W = GRID_W + PADDING + LABEL_PAD;
|
|
29
|
+
const SVG_H = GRID_H + PADDING + LABEL_PAD;
|
|
30
|
+
function impactIndex(risk) {
|
|
31
|
+
// Map impactUsd ranges to 0-4
|
|
32
|
+
if (risk.impactUsd < 1000) {
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
if (risk.impactUsd < 5000) {
|
|
36
|
+
return 1;
|
|
37
|
+
}
|
|
38
|
+
if (risk.impactUsd < 20000) {
|
|
39
|
+
return 2;
|
|
40
|
+
}
|
|
41
|
+
if (risk.impactUsd < 50000) {
|
|
42
|
+
return 3;
|
|
43
|
+
}
|
|
44
|
+
return 4;
|
|
45
|
+
}
|
|
46
|
+
function probIndex(risk) {
|
|
47
|
+
const p = risk.probability;
|
|
48
|
+
if (p <= 20) {
|
|
49
|
+
return 4;
|
|
50
|
+
} // row 4 = lowest
|
|
51
|
+
if (p <= 40) {
|
|
52
|
+
return 3;
|
|
53
|
+
}
|
|
54
|
+
if (p <= 60) {
|
|
55
|
+
return 2;
|
|
56
|
+
}
|
|
57
|
+
if (p <= 80) {
|
|
58
|
+
return 1;
|
|
59
|
+
}
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
function circleSizeFromUsd(usd) {
|
|
63
|
+
if (usd < 1000) {
|
|
64
|
+
return 8;
|
|
65
|
+
}
|
|
66
|
+
if (usd < 5000) {
|
|
67
|
+
return 12;
|
|
68
|
+
}
|
|
69
|
+
if (usd < 20000) {
|
|
70
|
+
return 16;
|
|
71
|
+
}
|
|
72
|
+
if (usd < 50000) {
|
|
73
|
+
return 20;
|
|
74
|
+
}
|
|
75
|
+
return 24;
|
|
76
|
+
}
|
|
77
|
+
function escapeHtml(s) {
|
|
78
|
+
return s
|
|
79
|
+
.replace(/&/g, '&')
|
|
80
|
+
.replace(/</g, '<')
|
|
81
|
+
.replace(/>/g, '>')
|
|
82
|
+
.replace(/"/g, '"');
|
|
83
|
+
}
|
|
84
|
+
function buildGridCells() {
|
|
85
|
+
const cells = [];
|
|
86
|
+
for (let row = 0; row < 5; row++) {
|
|
87
|
+
for (let col = 0; col < 5; col++) {
|
|
88
|
+
const x = PADDING + col * CELL;
|
|
89
|
+
const y = LABEL_PAD + row * CELL;
|
|
90
|
+
cells.push(`<rect x="${x}" y="${y}" width="${CELL}" height="${CELL}" fill="${QUADRANT_COLORS[row]?.[col] ?? '#d1fae5'}" stroke="#e5e7eb" stroke-width="1"/>`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return cells.join('\n ');
|
|
94
|
+
}
|
|
95
|
+
function buildAxisLabels() {
|
|
96
|
+
const parts = [];
|
|
97
|
+
// X-axis (Impact) labels
|
|
98
|
+
const impactLabels = ['Low', 'Med', 'High', 'V.High', 'Crit'];
|
|
99
|
+
for (let i = 0; i < 5; i++) {
|
|
100
|
+
const x = PADDING + i * CELL + CELL / 2;
|
|
101
|
+
const y = LABEL_PAD + GRID_H + 14;
|
|
102
|
+
parts.push(`<text x="${x}" y="${y}" text-anchor="middle" font-size="10" fill="#6b7280">${impactLabels[i]}</text>`);
|
|
103
|
+
}
|
|
104
|
+
// X-axis title
|
|
105
|
+
parts.push(`<text x="${PADDING + GRID_W / 2}" y="${SVG_H - 2}" text-anchor="middle" font-size="11" font-weight="600" fill="#374151">Impact</text>`);
|
|
106
|
+
// Y-axis (Probability) labels
|
|
107
|
+
const probLabels = ['80-100%', '60-80%', '40-60%', '20-40%', '0-20%'];
|
|
108
|
+
for (let i = 0; i < 5; i++) {
|
|
109
|
+
const y = LABEL_PAD + i * CELL + CELL / 2 + 4;
|
|
110
|
+
parts.push(`<text x="${PADDING - 4}" y="${y}" text-anchor="end" font-size="10" fill="#6b7280">${probLabels[i]}</text>`);
|
|
111
|
+
}
|
|
112
|
+
// Y-axis title (rotated)
|
|
113
|
+
const cx = 10;
|
|
114
|
+
const cy = LABEL_PAD + GRID_H / 2;
|
|
115
|
+
parts.push(`<text x="${cx}" y="${cy}" text-anchor="middle" font-size="11" font-weight="600" fill="#374151" transform="rotate(-90,${cx},${cy})">Probability</text>`);
|
|
116
|
+
return parts.join('\n ');
|
|
117
|
+
}
|
|
118
|
+
function buildRiskDots(risks) {
|
|
119
|
+
// Group risks in same cell to offset them
|
|
120
|
+
const cellMap = new Map();
|
|
121
|
+
for (const r of risks) {
|
|
122
|
+
const key = `${probIndex(r)},${impactIndex(r)}`;
|
|
123
|
+
const arr = cellMap.get(key) ?? [];
|
|
124
|
+
arr.push(r);
|
|
125
|
+
cellMap.set(key, arr);
|
|
126
|
+
}
|
|
127
|
+
const dots = [];
|
|
128
|
+
for (const [key, cellRisks] of cellMap) {
|
|
129
|
+
const parts = key.split(',').map(Number);
|
|
130
|
+
const row = parts[0] ?? 0;
|
|
131
|
+
const col = parts[1] ?? 0;
|
|
132
|
+
const cx = PADDING + col * CELL + CELL / 2;
|
|
133
|
+
const cy = LABEL_PAD + row * CELL + CELL / 2;
|
|
134
|
+
cellRisks.forEach((r, idx) => {
|
|
135
|
+
const offset = (idx - (cellRisks.length - 1) / 2) * 10;
|
|
136
|
+
const rx = cx + (cellRisks.length > 1 ? offset : 0);
|
|
137
|
+
const size = circleSizeFromUsd(r.impactUsd);
|
|
138
|
+
const color = CATEGORY_COLORS[r.category];
|
|
139
|
+
const label = escapeHtml(r.id);
|
|
140
|
+
dots.push(`<circle cx="${rx}" cy="${cy}" r="${size / 2}" fill="${color}" fill-opacity="0.85" stroke="white" stroke-width="1.5">` +
|
|
141
|
+
`<title>${label}: ${escapeHtml(r.description)} ($${r.impactUsd.toLocaleString()})</title>` +
|
|
142
|
+
`</circle>`);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return dots.join('\n ');
|
|
146
|
+
}
|
|
147
|
+
function buildLegend(risks) {
|
|
148
|
+
const categories = [...new Set(risks.map((r) => r.category))];
|
|
149
|
+
const parts = [];
|
|
150
|
+
const startY = LABEL_PAD + 4;
|
|
151
|
+
const startX = PADDING + GRID_W + 10;
|
|
152
|
+
if (startX + 90 > SVG_W + 110) {
|
|
153
|
+
return '';
|
|
154
|
+
} // no room
|
|
155
|
+
categories.forEach((cat, i) => {
|
|
156
|
+
const y = startY + i * 18;
|
|
157
|
+
const color = CATEGORY_COLORS[cat];
|
|
158
|
+
parts.push(`<circle cx="${startX + 6}" cy="${y}" r="5" fill="${color}"/>`);
|
|
159
|
+
parts.push(`<text x="${startX + 14}" y="${y + 4}" font-size="10" fill="#374151">${escapeHtml(cat)}</text>`);
|
|
160
|
+
});
|
|
161
|
+
return parts.join('\n ');
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Build a 5x5 risk matrix SVG.
|
|
165
|
+
* Returns empty string when risks array is empty.
|
|
166
|
+
*/
|
|
167
|
+
export function buildRiskMatrixSvg(risks) {
|
|
168
|
+
if (risks.length === 0) {
|
|
169
|
+
return '';
|
|
170
|
+
}
|
|
171
|
+
const legendWidth = 90;
|
|
172
|
+
const totalW = SVG_W + legendWidth;
|
|
173
|
+
return `<svg viewBox="0 0 ${totalW} ${SVG_H}" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Risk Matrix">
|
|
174
|
+
${buildGridCells()}
|
|
175
|
+
${buildAxisLabels()}
|
|
176
|
+
${buildRiskDots(risks)}
|
|
177
|
+
${buildLegend(risks)}
|
|
178
|
+
</svg>`;
|
|
179
|
+
}
|
|
180
|
+
export { IMPACT_LEVELS, PROB_LEVELS, CATEGORY_COLORS };
|
|
181
|
+
//# sourceMappingURL=risk-matrix-svg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk-matrix-svg.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/portal/risk-matrix-svg.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RiskRegister } from '../../../types/risk.js';
|
|
2
|
+
import type { Spec } from '../../../types/spec/core.js';
|
|
3
|
+
/**
|
|
4
|
+
* Generate the risks.html portal page.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateRiskPage(risks: RiskRegister[], specs: Spec[]): string;
|
|
7
|
+
//# sourceMappingURL=risk-page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk-page.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/portal/risk-page.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAsC,MAAM,wBAAwB,CAAC;AAC/F,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAC;AAsMxD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,CA6C7E"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { buildNavbar } from './portal-navbar.js';
|
|
2
|
+
import { getPortalThemeCSS } from './portal-theme.js';
|
|
3
|
+
import { buildRiskMatrixSvg } from './risk-matrix-svg.js';
|
|
4
|
+
import { buildRiskGaugeSvg } from './risk-gauge-svg.js';
|
|
5
|
+
function escapeHtml(s) {
|
|
6
|
+
return s
|
|
7
|
+
.replace(/&/g, '&')
|
|
8
|
+
.replace(/</g, '<')
|
|
9
|
+
.replace(/>/g, '>')
|
|
10
|
+
.replace(/"/g, '"');
|
|
11
|
+
}
|
|
12
|
+
const STATUS_BADGE = {
|
|
13
|
+
identified: 'planu-badge-muted',
|
|
14
|
+
mitigating: 'planu-badge-info',
|
|
15
|
+
mitigated: 'planu-badge-success',
|
|
16
|
+
accepted: 'planu-badge-warning',
|
|
17
|
+
materialized: 'planu-badge-danger',
|
|
18
|
+
};
|
|
19
|
+
function statusBadge(status) {
|
|
20
|
+
const cls = STATUS_BADGE[status];
|
|
21
|
+
return `<span class="planu-badge ${cls}">${escapeHtml(status)}</span>`;
|
|
22
|
+
}
|
|
23
|
+
function categoryBadge(cat) {
|
|
24
|
+
const colors = {
|
|
25
|
+
technical: 'planu-badge-info',
|
|
26
|
+
security: 'planu-badge-danger',
|
|
27
|
+
integration: 'planu-badge-warning',
|
|
28
|
+
dependency: 'planu-badge-muted',
|
|
29
|
+
organizational: 'planu-badge-muted',
|
|
30
|
+
data: 'planu-badge-success',
|
|
31
|
+
};
|
|
32
|
+
return `<span class="planu-badge ${colors[cat]}">${escapeHtml(cat)}</span>`;
|
|
33
|
+
}
|
|
34
|
+
function buildRiskTable(allRisks, specMap) {
|
|
35
|
+
if (allRisks.length === 0) {
|
|
36
|
+
return `<p class="empty-message">No risks registered yet.</p>`;
|
|
37
|
+
}
|
|
38
|
+
const rows = allRisks
|
|
39
|
+
.map((r) => {
|
|
40
|
+
const specTitle = specMap.get(r.specId) ?? r.specId;
|
|
41
|
+
return `<tr>
|
|
42
|
+
<td>${escapeHtml(r.id)}</td>
|
|
43
|
+
<td title="${escapeHtml(r.specId)}">${escapeHtml(specTitle)}</td>
|
|
44
|
+
<td>${escapeHtml(r.description)}</td>
|
|
45
|
+
<td>${categoryBadge(r.category)}</td>
|
|
46
|
+
<td class="num">${r.probability}%</td>
|
|
47
|
+
<td class="num">$${r.impactUsd.toLocaleString()}</td>
|
|
48
|
+
<td class="num">${r.impactDays}d</td>
|
|
49
|
+
<td>${escapeHtml(r.mitigationPlan || '—')}</td>
|
|
50
|
+
<td>${escapeHtml(r.owner || '—')}</td>
|
|
51
|
+
<td>${statusBadge(r.status)}</td>
|
|
52
|
+
</tr>`;
|
|
53
|
+
})
|
|
54
|
+
.join('\n');
|
|
55
|
+
return `<div class="table-wrap">
|
|
56
|
+
<table class="risk-table sortable">
|
|
57
|
+
<thead>
|
|
58
|
+
<tr>
|
|
59
|
+
<th>ID</th>
|
|
60
|
+
<th>Spec</th>
|
|
61
|
+
<th>Description</th>
|
|
62
|
+
<th>Category</th>
|
|
63
|
+
<th class="sortable-col">Probability</th>
|
|
64
|
+
<th class="sortable-col">Impact $</th>
|
|
65
|
+
<th class="sortable-col">Impact Days</th>
|
|
66
|
+
<th>Mitigation</th>
|
|
67
|
+
<th>Owner</th>
|
|
68
|
+
<th>Status</th>
|
|
69
|
+
</tr>
|
|
70
|
+
</thead>
|
|
71
|
+
<tbody>
|
|
72
|
+
${rows}
|
|
73
|
+
</tbody>
|
|
74
|
+
</table>
|
|
75
|
+
</div>`;
|
|
76
|
+
}
|
|
77
|
+
function buildCoverageSection(allRisks) {
|
|
78
|
+
if (allRisks.length === 0) {
|
|
79
|
+
return '';
|
|
80
|
+
}
|
|
81
|
+
const total = allRisks.length;
|
|
82
|
+
const withPlan = allRisks.filter((r) => r.mitigationPlan && r.mitigationPlan.trim().length > 0).length;
|
|
83
|
+
const mitigated = allRisks.filter((r) => r.status === 'mitigated').length;
|
|
84
|
+
const noOwner = allRisks.filter((r) => !r.owner || r.owner.trim() === '').length;
|
|
85
|
+
const planPct = Math.round((withPlan / total) * 100);
|
|
86
|
+
const mitigatedPct = Math.round((mitigated / total) * 100);
|
|
87
|
+
const warning = noOwner > 0
|
|
88
|
+
? `<div class="coverage-warning">⚠️ <strong>${noOwner}</strong> risk${noOwner > 1 ? 's' : ''} without an assigned owner.</div>`
|
|
89
|
+
: '';
|
|
90
|
+
return `<section class="planu-card section-card">
|
|
91
|
+
<h2>Mitigation Coverage</h2>
|
|
92
|
+
<div class="coverage-grid">
|
|
93
|
+
<div class="coverage-item">
|
|
94
|
+
<span class="coverage-pct">${planPct}%</span>
|
|
95
|
+
<span class="coverage-label">With Mitigation Plan</span>
|
|
96
|
+
</div>
|
|
97
|
+
<div class="coverage-item">
|
|
98
|
+
<span class="coverage-pct coverage-green">${mitigatedPct}%</span>
|
|
99
|
+
<span class="coverage-label">Mitigated</span>
|
|
100
|
+
</div>
|
|
101
|
+
<div class="coverage-item">
|
|
102
|
+
<span class="coverage-pct coverage-red">${noOwner}</span>
|
|
103
|
+
<span class="coverage-label">Without Owner</span>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
${warning}
|
|
107
|
+
</section>`;
|
|
108
|
+
}
|
|
109
|
+
function buildScoreCard(registers, allRisks) {
|
|
110
|
+
const avgScore = registers.length > 0
|
|
111
|
+
? Math.round(registers.reduce((s, r) => s + r.aggregateRiskScore, 0) / registers.length)
|
|
112
|
+
: 0;
|
|
113
|
+
const highCount = allRisks.filter((r) => r.probability >= 60 && r.impactUsd >= 5000).length;
|
|
114
|
+
const criticalCount = allRisks.filter((r) => r.probability >= 80 && r.impactUsd >= 20000).length;
|
|
115
|
+
const gaugeSvg = buildRiskGaugeSvg(avgScore);
|
|
116
|
+
return `<section class="planu-card section-card score-card">
|
|
117
|
+
<h2>Risk Score</h2>
|
|
118
|
+
<div class="score-layout">
|
|
119
|
+
<div class="gauge-wrap">${gaugeSvg}</div>
|
|
120
|
+
<div class="score-stats">
|
|
121
|
+
<div class="stat-item">
|
|
122
|
+
<span class="stat-num">${allRisks.length}</span>
|
|
123
|
+
<span class="stat-label">Total Risks</span>
|
|
124
|
+
</div>
|
|
125
|
+
<div class="stat-item stat-warn">
|
|
126
|
+
<span class="stat-num">${highCount}</span>
|
|
127
|
+
<span class="stat-label">High Priority</span>
|
|
128
|
+
</div>
|
|
129
|
+
<div class="stat-item stat-danger">
|
|
130
|
+
<span class="stat-num">${criticalCount}</span>
|
|
131
|
+
<span class="stat-label">Critical</span>
|
|
132
|
+
</div>
|
|
133
|
+
<div class="stat-item">
|
|
134
|
+
<span class="stat-num">${registers.length}</span>
|
|
135
|
+
<span class="stat-label">Specs with Risks</span>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</section>`;
|
|
140
|
+
}
|
|
141
|
+
function buildPageCSS() {
|
|
142
|
+
return `
|
|
143
|
+
body { font-family: system-ui, sans-serif; margin: 0; padding: 0 16px 48px; background: var(--planu-bg); color: var(--planu-text); }
|
|
144
|
+
.page-title { font-size: 1.6rem; font-weight: 700; margin: 0 0 6px; }
|
|
145
|
+
.page-subtitle { color: #6b7280; margin: 0 0 24px; font-size: 0.95rem; }
|
|
146
|
+
.section-card { margin-bottom: 24px; }
|
|
147
|
+
h2 { font-size: 1.1rem; font-weight: 600; margin: 0 0 16px; color: var(--planu-primary); }
|
|
148
|
+
.matrix-wrap { overflow-x: auto; }
|
|
149
|
+
.matrix-wrap svg { max-width: 100%; height: auto; }
|
|
150
|
+
.table-wrap { overflow-x: auto; }
|
|
151
|
+
.risk-table { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
|
|
152
|
+
.risk-table th { background: #f3f4f6; text-align: left; padding: 8px 10px; font-weight: 600; white-space: nowrap; border-bottom: 2px solid var(--planu-border); }
|
|
153
|
+
.risk-table td { padding: 8px 10px; border-bottom: 1px solid var(--planu-border); vertical-align: top; }
|
|
154
|
+
.risk-table tr:hover td { background: #f9fafb; }
|
|
155
|
+
.risk-table .num { text-align: right; white-space: nowrap; }
|
|
156
|
+
.score-layout { display: flex; align-items: flex-start; gap: 24px; flex-wrap: wrap; }
|
|
157
|
+
.gauge-wrap { width: 200px; flex-shrink: 0; }
|
|
158
|
+
.gauge-wrap svg { width: 100%; height: auto; }
|
|
159
|
+
.score-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; flex: 1; }
|
|
160
|
+
.stat-item { text-align: center; padding: 12px; background: #f9fafb; border-radius: 8px; }
|
|
161
|
+
.stat-num { display: block; font-size: 1.8rem; font-weight: 700; color: var(--planu-primary); }
|
|
162
|
+
.stat-warn .stat-num { color: var(--planu-warning); }
|
|
163
|
+
.stat-danger .stat-num { color: var(--planu-danger); }
|
|
164
|
+
.stat-label { font-size: 0.78rem; color: #6b7280; }
|
|
165
|
+
.coverage-grid { display: flex; gap: 24px; flex-wrap: wrap; }
|
|
166
|
+
.coverage-item { text-align: center; min-width: 100px; }
|
|
167
|
+
.coverage-pct { display: block; font-size: 2rem; font-weight: 700; color: var(--planu-primary); }
|
|
168
|
+
.coverage-green { color: var(--planu-success); }
|
|
169
|
+
.coverage-red { color: var(--planu-danger); }
|
|
170
|
+
.coverage-label { font-size: 0.82rem; color: #6b7280; }
|
|
171
|
+
.coverage-warning { margin-top: 12px; padding: 10px 14px; background: #fef3c7; border-radius: 8px; font-size: 0.88rem; color: #92400e; }
|
|
172
|
+
.empty-state { text-align: center; padding: 48px 24px; color: #6b7280; }
|
|
173
|
+
.empty-state h3 { font-size: 1.2rem; margin-bottom: 8px; }
|
|
174
|
+
.empty-message { color: #9ca3af; font-style: italic; }`;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Generate the risks.html portal page.
|
|
178
|
+
*/
|
|
179
|
+
export function generateRiskPage(risks, specs) {
|
|
180
|
+
const specMap = new Map(specs.map((s) => [s.id, s.title]));
|
|
181
|
+
const allRisks = risks.flatMap((r) => r.risks);
|
|
182
|
+
const navbar = buildNavbar('risks', '');
|
|
183
|
+
const themeCSS = getPortalThemeCSS();
|
|
184
|
+
const pageCSS = buildPageCSS();
|
|
185
|
+
const matrixSvg = buildRiskMatrixSvg(allRisks);
|
|
186
|
+
const matrixSection = allRisks.length > 0
|
|
187
|
+
? `<section class="planu-card section-card">
|
|
188
|
+
<h2>Risk Matrix</h2>
|
|
189
|
+
<div class="matrix-wrap">${matrixSvg}</div>
|
|
190
|
+
</section>`
|
|
191
|
+
: '';
|
|
192
|
+
const bodyContent = allRisks.length === 0
|
|
193
|
+
? `<div class="empty-state"><h3>No risk data available</h3><p>Use <code>estimate</code> with risk analysis to populate this page.</p></div>`
|
|
194
|
+
: `${buildScoreCard(risks, allRisks)}
|
|
195
|
+
${matrixSection}
|
|
196
|
+
<section class="planu-card section-card">
|
|
197
|
+
<h2>Risk Registry</h2>
|
|
198
|
+
${buildRiskTable(allRisks, specMap)}
|
|
199
|
+
</section>
|
|
200
|
+
${buildCoverageSection(allRisks)}`;
|
|
201
|
+
return `<!DOCTYPE html>
|
|
202
|
+
<html lang="en">
|
|
203
|
+
<head>
|
|
204
|
+
<meta charset="UTF-8">
|
|
205
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
206
|
+
<title>Risks — Planu Portal</title>
|
|
207
|
+
<style>${themeCSS}${pageCSS}</style>
|
|
208
|
+
</head>
|
|
209
|
+
<body>
|
|
210
|
+
${navbar}
|
|
211
|
+
<main>
|
|
212
|
+
<h1 class="page-title">⚠️ Risk Register</h1>
|
|
213
|
+
<p class="page-subtitle">Risk matrix, registry, and mitigation coverage across all specs.</p>
|
|
214
|
+
${bodyContent}
|
|
215
|
+
</main>
|
|
216
|
+
</body>
|
|
217
|
+
</html>`;
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=risk-page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk-page.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/portal/risk-page.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Spec } from '../../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generate the full roadmap.html page for the Planu portal.
|
|
4
|
+
* Returns an HTML string ready to write to disk.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateRoadmapPage(specs: Spec[], ganttStartDate?: string): string;
|
|
7
|
+
//# sourceMappingURL=roadmap-page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roadmap-page.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/portal/roadmap-page.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAKpD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAqClF"}
|