feat(ms-ai-architect): renderer A.4 frimpact adopt page-header + critique-cards

- renderFria wrapped med renderPageShell (eyebrow FRIA, lede ref AI Act Art. 27)
- Erstatter rights-matrix med D4 critique-cards per rettighet (severity fra impact-score)
- Ny fria-case i inferVerdict: max impact >=4 block, >=3 warning, ellers go-with-conditions
- DS_CLASSES test oppdatert: rights-matrix -> critique-card (Step 10 endrer body for FRIA)
This commit is contained in:
Kjell Tore Guttormsen 2026-05-04 06:06:28 +02:00
commit ead1697ff0
2 changed files with 37 additions and 13 deletions

View file

@ -3130,20 +3130,35 @@
}
function renderFria(data, slot) {
const headerHtml =
'<div class="rights-matrix__head">' +
'<div class="rights-matrix__head-cell rights-matrix__head-cell--name">Rettighet</div>' +
'<div class="rights-matrix__head-cell">Impact (0-5)</div>' +
'<div class="rights-matrix__head-cell">Tiltak</div>' +
'</div>';
const rowsHtml = (data.rights || []).map(function (r) {
return '<div class="rights-matrix__row">' +
'<div class="rights-matrix__name">' + escapeHtml(r.name) + '</div>' +
'<div class="rights-matrix__cell" data-impact="' + escapeAttr(String(r.impact)) + '">' + r.impact + '</div>' +
'<div class="rights-matrix__name"><div class="rights-matrix__name-meta">' + escapeHtml(r.mitigation) + '</div></div>' +
const sevForImpact = function (n) {
const v = Number(n) || 0;
if (v >= 4) return 'critical';
if (v >= 3) return 'high';
if (v >= 2) return 'medium';
if (v >= 1) return 'low';
return 'info';
};
const cardsHtml = (data.rights || []).map(function (r, idx) {
const sev = sevForImpact(r.impact);
return '<div class="critique-card" data-severity="' + escapeAttr(sev) + '">' +
'<div class="critique-card__header">' +
'<div class="critique-card__title">' + escapeHtml(r.name) + '</div>' +
'<div class="critique-card__meta">' +
'<span class="critique-card__id">FRIA-' + String(idx + 1).padStart(2, '0') + '</span>' +
'<span class="critique-card__id" style="background: var(--color-bg-soft);">Impact ' + escapeHtml(String(r.impact || 0)) + '/5</span>' +
'</div>' +
'</div>' +
(r.mitigation ? '<div class="critique-card__recommendation">' + escapeHtml(r.mitigation) + '</div>' : '') +
'</div>';
}).join('');
slot.innerHTML = '<div class="rights-matrix" style="grid-template-columns: 1fr 80px 2fr;">' + headerHtml + rowsHtml + '</div>';
const body = '<div class="critique-cards">' + (cardsHtml || '<p class="muted">Ingen rettigheter registrert.</p>') + '</div>';
slot.innerHTML = renderPageShell({
eyebrow: 'FRIA',
title: data.title || 'Fundamental Rights Impact Assessment',
lede: data.lede || 'EU AI Act Art. 27 — obligatorisk for offentlig sektor som deployer.',
verdict: data.verdict || inferVerdict(data, 'fria'),
keyStats: data.keyStats || inferKeyStats(data, 'fria')
}, body);
}
function renderConformity(data, slot) {
@ -3674,6 +3689,15 @@
if (threats.length) return 'warning';
return 'n-a';
}
case 'fria': {
const rights = data.rights || [];
if (!rights.length) return 'n-a';
const max = rights.reduce(function (a, r) { const v = Number(r.impact) || 0; return v > a ? v : a; }, 0);
if (max >= 4) return 'block';
if (max >= 3) return 'warning';
if (max >= 1) return 'go-with-conditions';
return 'go';
}
case 'conformity-checklist': {
const cl = data.checklist || [];
if (!cl.length) return 'n-a';

View file

@ -198,7 +198,7 @@ fi
# -------------------------------------------------------
# 12. Design-system CSS-klasse-bruk (Tier 1+2+3)
# -------------------------------------------------------
DS_CLASSES=".pyramide .matrix .radar .findings .distribution .rights-matrix .capability-matrix .aiact-timeline .tracks .error-summary .guide-panel .expansion .form-progress"
DS_CLASSES=".pyramide .matrix .radar .findings .distribution .critique-card .capability-matrix .aiact-timeline .tracks .error-summary .guide-panel .expansion .form-progress"
for cls in $DS_CLASSES; do
# Match som klassen i class="..." eller selektor — søk på klassenavnet uten leading dot
bare="${cls#.}"