feat(ms-ai-architect): renderer A.2 requirements adopt page-header + scenario-cards + E7

- renderRequirements wrapped med renderPageShell (eyebrow KRAV, verdict via requirements-list)
- scenario-card-grid: gruppert pa source_article, status fra dominant (met/partial/missing)
- expansion-card per krav (E7): severity-dot + title + chev, body med dl
- data-action requirement-expand wired for klikk-toggle (handler kommer i Sesjon 6)
This commit is contained in:
Kjell Tore Guttormsen 2026-05-04 06:04:20 +02:00
commit 5f461bfe20

View file

@ -3040,6 +3040,7 @@
}
function renderRequirements(data, slot) {
const items = data.items || [];
const sevForStatus = function (status) {
const s = (status || '').toLowerCase();
if (s === 'met') return 'low';
@ -3047,23 +3048,58 @@
if (s === 'missing') return 'critical';
return 'info';
};
const items = (data.items || []).map(function (it, idx) {
return '<li class="findings__item" data-status="' + escapeAttr(it.status || '') + '">' +
'<span class="findings__item-severity-dot" data-severity="' + escapeAttr(sevForStatus(it.status)) + '"></span>' +
'<span class="findings__item-id">R-' + String(idx + 1).padStart(2, '0') + '</span>' +
'<span class="findings__item-title">' + escapeHtml(it.requirement) + '</span>' +
'<span class="findings__item-meta">Kilde: ' + escapeHtml(it.source_article || '—') + ' · Status: ' + escapeHtml(it.status || '—') + '</span>' +
'</li>';
}).join('');
slot.innerHTML =
'<div class="findings">' +
'<div class="findings__list">' +
'<div class="findings__group">' +
'<div class="findings__group-header"><span>Krav</span><span>' + (data.items || []).length + '</span></div>' +
'<ul class="findings__items">' + items + '</ul>' +
'</div>' +
'</div>' +
'</div>';
const dominantStatus = function (group) {
if (group.some(function (it) { return /missing/i.test(it.status); })) return 'missing';
if (group.some(function (it) { return /partial/i.test(it.status); })) return 'partial';
return 'met';
};
// Group by source_article (Art. X) for scenario-card-grid.
const groups = {};
items.forEach(function (it) {
const key = it.source_article || 'Andre';
if (!groups[key]) groups[key] = [];
groups[key].push(it);
});
const groupKeys = Object.keys(groups).sort();
const cardsHtml = groupKeys.length ? '<div class="scenario-card-grid">' + groupKeys.map(function (k) {
const group = groups[k];
const status = dominantStatus(group);
return '<div class="scenario-card" data-status="' + escapeAttr(status) + '">' +
'<div class="scenario-card__head">' +
'<span class="scenario-card__source">' + escapeHtml(k) + '</span>' +
'<span class="scenario-card__count">' + group.length + ' krav</span>' +
'</div>' +
'<p class="scenario-card__title">' + escapeHtml(group[0].requirement) + (group.length > 1 ? ' (+' + (group.length - 1) + ')' : '') + '</p>' +
'</div>';
}).join('') + '</div>' : '';
const expansionsHtml = items.length ? items.map(function (it, idx) {
const sev = sevForStatus(it.status);
return '<div class="expansion" aria-expanded="false">' +
'<button type="button" class="expansion__head" data-action="requirement-expand" data-idx="' + idx + '">' +
'<span class="findings__item-severity-dot" data-severity="' + escapeAttr(sev) + '"></span>' +
'<span class="expansion__title">' +
'<span class="expansion__title-main">R-' + String(idx + 1).padStart(2, '0') + ' — ' + escapeHtml(it.requirement) + '</span>' +
'<span class="expansion__title-sub">Kilde: ' + escapeHtml(it.source_article || '—') + ' · Status: ' + escapeHtml(it.status || '—') + '</span>' +
'</span>' +
'<span class="expansion__chev" aria-hidden="true"></span>' +
'</button>' +
'<div class="expansion__body"><div class="expansion__body-inner"><div>' +
'<dl><dt>Kilde</dt><dd>' + escapeHtml(it.source_article || '—') + '</dd>' +
'<dt>Status</dt><dd>' + escapeHtml(it.status || '—') + '</dd></dl>' +
'</div></div></div>' +
'</div>';
}).join('') : '';
const body = cardsHtml + (expansionsHtml ? '<div class="findings">' + expansionsHtml + '</div>' : '');
slot.innerHTML = renderPageShell({
eyebrow: 'KRAV',
title: data.title || 'AI Act-krav per risiko og rolle',
lede: data.lede || 'Konkrete forpliktelser gruppert etter Art-paragraf med detaljer per krav.',
verdict: data.verdict || inferVerdict(data, 'requirements-list'),
keyStats: data.keyStats || inferKeyStats(data, 'requirements-list')
}, body);
}
function renderTransparency(data, slot) {