fix(ms-ai-architect): playground v1.13.0 — visuelle DS-bugs
Fix-pakke som speiler llm-security v7.6.1 (commit f9b555a). Samme klasse
visuelle bugs identifisert via parallell DS-analyse av playground-rendrere.
- B1: renderFindingsBlock + renderRequirements bytter <div class="findings">
outer (DS grid 360px+1fr klemte indre struktur til 360px-kolonne, lot
1fr-detail-panel-kolonnen stå tom) til <section class="report-meta">.
BEM-strukturen findings__list > findings__group > findings__items uendret.
- B2: lokal .report-table CSS for 6+ rapporter (Trusler, Kostnadsoversikt,
TCO, Risiko-tabell, Key Metrics) som manglet styling — DS implementerer
ikke klassen. Speilet lokal styling fra llm-security v7.6.1.
- B3: ROS-matrise-bobler bytter <span> til <button type="button"
data-threat-id="..." aria-label="..."> med document-level click-handler
som scroller smooth til tilsvarende rad i Trusler-tabellen og
highlighter raden i 1.6 sek. Lokal CSS for cursor:pointer, hover
scale(1.15), :focus-visible outline.
- B4: renderRadarSvg bumpet 300x300 til 380x380, R fra 100 til 125,
label-offset fra R+25 til R+28, dynamisk text-anchor basert på
horisontal-posisjon for å unngå at bottom-labels overlapper hverandre
ved 6+ akser (typisk for ROS-rapport med 7 risiko-dimensjoner).
- B5: lokal .recommendation-card__body { overflow-wrap: anywhere;
word-break: break-word } for å forhindre at lange single-line tekster
(URLer, owner-tags, dato) skubber innhold ut av viewport i grid-cellen.
tests/test-playground-v3.sh: DS-klasse-assertion oppdatert fra .findings
til .findings__list (BEM-list er fortsatt i bruk; outer grid-container
bevisst fjernet i B1).
Verifisering:
- 22/22 smoke-test PASS (B1-B5 grep-asserts)
- 271/271 playground E2E PASS (201 statisk-struktur + 70 parser-fixtures)
- 219 plugin-validering PASS
- 42 KB-update test PASS
Versjon: v1.12.0 -> v1.13.0 (plugin.json, README badge, README
version-history, CHANGELOG, ROADMAP, TODO, plugin CLAUDE.md
playground-header, root README plugin-list, root CLAUDE.md plugin-list).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
b7d64a6d2b
commit
121c5cc677
8 changed files with 108 additions and 17 deletions
|
|
@ -168,6 +168,29 @@
|
|||
.suppressed-panel__list { display: flex; flex-direction: column; gap: var(--space-2); margin: var(--space-2) 0 0 0; }
|
||||
.suppressed-panel__item { padding: var(--space-2) var(--space-3); background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-sm); font-size: var(--font-size-sm); color: var(--color-text-secondary); display: flex; gap: var(--space-3); align-items: baseline; }
|
||||
.suppressed-panel__id { font-family: var(--font-family-mono); font-size: var(--font-size-xs); color: var(--color-text-tertiary); }
|
||||
|
||||
/* v1.13.0 fix (B2): .report-table — DS har ikke implementert denne klassen, men
|
||||
playground-rendrere bruker den i 6+ rapporter (Trusler, Kostnadsoversikt,
|
||||
TCO, Risiko-tabell, Key Metrics). Lokal styling som komplementerer DS-tokens.
|
||||
Speilet fra llm-security v7.6.1 commit f9b555a. */
|
||||
.report-table { width: 100%; border-collapse: collapse; margin: var(--space-3) 0; font-size: var(--font-size-sm); }
|
||||
.report-table th { text-align: left; padding: 8px 12px; border-bottom: 2px solid var(--color-border-moderate); background: var(--color-bg-soft); font-weight: var(--font-weight-semibold); color: var(--color-text-secondary); text-transform: uppercase; font-size: 11px; letter-spacing: 0.04em; }
|
||||
.report-table td { padding: 8px 12px; border-bottom: 1px solid var(--color-border-subtle); vertical-align: top; color: var(--color-text-primary); }
|
||||
.report-table tr:last-child td { border-bottom: none; }
|
||||
.report-table tbody tr:hover { background: var(--color-bg-soft); }
|
||||
.report-table code { font-family: var(--font-family-mono); font-size: 12px; background: var(--color-surface-sunken); padding: 1px 6px; border-radius: var(--radius-sm); }
|
||||
|
||||
/* v1.13.0 fix (B5): recommendation-card body kan inneholde lange single-line
|
||||
tekster (URLer, owner-tags, dato). Tving word-wrap så grid-celle (auto + 1fr)
|
||||
ikke skubber innhold utenfor viewport. */
|
||||
.recommendation-card__body { overflow-wrap: anywhere; word-break: break-word; }
|
||||
|
||||
/* v1.13.0 fix (B3): matrix-bobler i ROS-matrise skal være klikkbare.
|
||||
DS har hover på cellene, men bobler er <span> uten cursor. Klikk-handler
|
||||
scroller til tilsvarende rad i Trusler-tabellen. */
|
||||
.matrix__bubble { cursor: pointer; transition: transform var(--duration-fast) var(--ease-default); }
|
||||
.matrix__bubble:hover { transform: scale(1.15); }
|
||||
.matrix__bubble:focus-visible { outline: 2px solid var(--color-primary-500); outline-offset: 2px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -3272,6 +3295,9 @@
|
|||
}
|
||||
|
||||
function renderFindingsBlock(findings, label) {
|
||||
// v1.13.0 fix (B1): DS' .findings er grid 360px+1fr (list+detail-panel).
|
||||
// Vi har bare list-kolonnen; bruk <section class="report-meta"> som outer
|
||||
// for å beholde findings__list-strukturen uten å bli klemt til 360px.
|
||||
const items = findings.map(function (f) {
|
||||
return '<li class="findings__item">' +
|
||||
'<span class="findings__item-severity-dot" data-severity="' + escapeAttr(f.severity || 'info') + '"></span>' +
|
||||
|
|
@ -3280,14 +3306,15 @@
|
|||
'<span class="findings__item-meta">Lokasjon: ' + escapeHtml(f.location || '—') + ' · Severity: ' + escapeHtml(f.severity || '—') + '</span>' +
|
||||
'</li>';
|
||||
}).join('');
|
||||
return '<div class="findings">' +
|
||||
return '<section class="report-meta">' +
|
||||
'<h4>' + escapeHtml(label) + '</h4>' +
|
||||
'<div class="findings__list">' +
|
||||
'<div class="findings__group">' +
|
||||
'<div class="findings__group-header"><span>' + escapeHtml(label) + '</span><span>' + findings.length + '</span></div>' +
|
||||
'<ul class="findings__items">' + items + '</ul>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
'</section>';
|
||||
}
|
||||
|
||||
function renderMatrixHtml(data, cons_max) {
|
||||
|
|
@ -3307,12 +3334,14 @@
|
|||
for (let prob = 1; prob <= probSize; prob++) {
|
||||
const score = prob * cons;
|
||||
const items = byPC[prob + '_' + cons] || [];
|
||||
// v1.13.0 fix (B3): bobler er nå <button> så de er klikkbare og fokuserbare.
|
||||
// data-threat-id mapper til rad i Trusler-tabellen via document-level handler.
|
||||
const bubblesHtml = items.length
|
||||
? '<div class="matrix__cell-bubbles">' +
|
||||
items.slice(0, 3).map(function (it, i) {
|
||||
return '<span class="matrix__bubble" title="' + escapeAttr(it.label || '') + '">' + (i + 1) + '</span>';
|
||||
return '<button type="button" class="matrix__bubble" data-threat-id="' + escapeAttr(it.id || it.label || '') + '" title="' + escapeAttr(it.label || '') + '" aria-label="Trussel: ' + escapeAttr(it.label || it.id || '') + '">' + (i + 1) + '</button>';
|
||||
}).join('') +
|
||||
(items.length > 3 ? '<span class="matrix__bubble matrix__bubble--count">+' + (items.length - 3) + '</span>' : '') +
|
||||
(items.length > 3 ? '<button type="button" class="matrix__bubble matrix__bubble--count" aria-label="' + (items.length - 3) + ' flere trusler">+' + (items.length - 3) + '</button>' : '') +
|
||||
'</div>'
|
||||
: '';
|
||||
html += '<div class="matrix__cell" data-score="' + score + '">' +
|
||||
|
|
@ -3332,8 +3361,13 @@
|
|||
|
||||
function renderRadarSvg(axes) {
|
||||
if (!axes || !axes.length) return '';
|
||||
// v1.13.0 fix (B4): bump SVG fra 300×300 til 380×380, R fra 100 til 125,
|
||||
// label-offset fra R+25 til R+28, og dynamisk text-anchor basert på
|
||||
// horisontal-posisjon. Forhindrer at bottom-labels overlapper ved 6+
|
||||
// akser (typisk for ROS med 7 risiko-dimensjoner). Speilet fra
|
||||
// llm-security v7.6.1 commit f9b555a.
|
||||
const N = axes.length;
|
||||
const cx = 150, cy = 150, R = 100;
|
||||
const SIZE = 380, cx = SIZE / 2, cy = SIZE / 2, R = 125;
|
||||
const points = axes.map(function (a, i) {
|
||||
const angle = (i / N) * 2 * Math.PI - Math.PI / 2;
|
||||
const r = R * (Math.max(0, Math.min(5, a.score)) / 5);
|
||||
|
|
@ -3341,9 +3375,11 @@
|
|||
}).join(' ');
|
||||
const labels = axes.map(function (a, i) {
|
||||
const angle = (i / N) * 2 * Math.PI - Math.PI / 2;
|
||||
const x = cx + (R + 25) * Math.cos(angle);
|
||||
const y = cy + (R + 25) * Math.sin(angle);
|
||||
return '<text class="radar__label" x="' + x.toFixed(1) + '" y="' + y.toFixed(1) + '" text-anchor="middle" dominant-baseline="middle">' + escapeHtml(a.name) + '</text>';
|
||||
const x = cx + (R + 28) * Math.cos(angle);
|
||||
const y = cy + (R + 28) * Math.sin(angle);
|
||||
const dx = Math.cos(angle);
|
||||
const anchor = Math.abs(dx) < 0.2 ? 'middle' : (dx > 0 ? 'start' : 'end');
|
||||
return '<text class="radar__label" x="' + x.toFixed(1) + '" y="' + y.toFixed(1) + '" text-anchor="' + anchor + '" dominant-baseline="middle">' + escapeHtml(a.name) + '</text>';
|
||||
}).join('');
|
||||
const spokes = axes.map(function (a, i) {
|
||||
const angle = (i / N) * 2 * Math.PI - Math.PI / 2;
|
||||
|
|
@ -3352,7 +3388,7 @@
|
|||
return '<line class="radar__axis" x1="' + cx + '" y1="' + cy + '" x2="' + x.toFixed(1) + '" y2="' + y.toFixed(1) + '"/>';
|
||||
}).join('');
|
||||
return '<div class="radar"><div class="radar__chart">' +
|
||||
'<svg class="radar__svg" viewBox="0 0 300 300">' +
|
||||
'<svg class="radar__svg" viewBox="0 0 ' + SIZE + ' ' + SIZE + '">' +
|
||||
'<circle class="radar__grid-line" cx="' + cx + '" cy="' + cy + '" r="' + R + '" fill="none"/>' +
|
||||
'<circle class="radar__grid-line" cx="' + cx + '" cy="' + cy + '" r="' + (R * 0.6) + '" fill="none"/>' +
|
||||
spokes + labels +
|
||||
|
|
@ -3467,7 +3503,9 @@
|
|||
'</div>';
|
||||
}).join('') : '';
|
||||
|
||||
const body = cardsHtml + (expansionsHtml ? '<div class="findings">' + expansionsHtml + '</div>' : '');
|
||||
// v1.13.0 fix (B1): bytt .findings-outer til .report-meta-wrapper
|
||||
// (DS' .findings er grid 360px+1fr, klemmer expansion-list til 360px).
|
||||
const body = cardsHtml + (expansionsHtml ? '<section class="report-meta">' + expansionsHtml + '</section>' : '');
|
||||
slot.innerHTML = renderPageShell({
|
||||
eyebrow: 'KRAV',
|
||||
title: data.title || 'AI Act-krav per risiko og rolle',
|
||||
|
|
@ -5243,6 +5281,32 @@
|
|||
if (handler) handler(ev, actionEl);
|
||||
});
|
||||
|
||||
// v1.13.0 fix (B3): matrix-bobler klikkbare. Klikk scroller til tilsvarende
|
||||
// rad i Trusler-tabellen og fremhever den kort. Bruker data-threat-id som
|
||||
// anker (matchet mot første kolonne i tabellen). Speilet fra llm-security
|
||||
// v7.6.1 commit f9b555a.
|
||||
document.addEventListener('click', function (ev) {
|
||||
const bubble = ev.target.closest('.matrix__bubble[data-threat-id]');
|
||||
if (!bubble) return;
|
||||
const threatId = bubble.getAttribute('data-threat-id');
|
||||
if (!threatId) return;
|
||||
const tables = document.querySelectorAll('table.report-table');
|
||||
for (let t = 0; t < tables.length; t++) {
|
||||
const rows = tables[t].querySelectorAll('tbody tr');
|
||||
for (let r = 0; r < rows.length; r++) {
|
||||
const firstCell = rows[r].querySelector('td');
|
||||
if (firstCell && firstCell.textContent.trim() === threatId) {
|
||||
rows[r].scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
const orig = rows[r].style.background;
|
||||
rows[r].style.background = 'var(--color-primary-100, var(--color-bg-soft))';
|
||||
rows[r].style.transition = 'background var(--duration-base) var(--ease-default)';
|
||||
setTimeout(function () { rows[r].style.background = orig; }, 1600);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ACTIONS['onboarding-toggle-group'] = function (ev, el) {
|
||||
const exp = el.closest('.expansion');
|
||||
if (!exp) return;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue