feat(privacy): surface the customer-data scan above the hardware report

- Move the "Customer data" panel to the top of the data section (above the
  chart iframe); header + customer guess always visible, findings table
  collapsed by default and expandable.
- Add a chart top-notice (above Board/CPUs) summarizing the scan via the
  viewer's standard NoticeTitle/NoticeBody - interim until chart custom panels.
- Allowlist ieisystem.com (IEI = Inspur brand infrastructure).
- Add chart-custom-panels-spec.md: a reusable, versioned contract proposal for
  host-supplied panels across every app embedding reanimator/chart.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Mikhail Chusavitin
2026-09-02 16:19:57 +03:00
co-authored by Claude Sonnet 5
parent 4a4910f207
commit fb0b0e3c55
6 changed files with 369 additions and 33 deletions
+22 -8
View File
@@ -1484,16 +1484,30 @@ async function loadPrivacyScan() {
rows.appendChild(tr);
}
const findingsBox = document.getElementById('privacy-findings');
const toggle = document.getElementById('privacy-toggle');
if (findings.length === 0) {
if (findingsBox) findingsBox.style.display = 'none';
if (toggle) toggle.style.visibility = 'hidden';
} else {
if (toggle) {
toggle.style.visibility = '';
toggle.textContent = privacyCollapsed ? '▼' : '▲';
}
if (findingsBox) findingsBox.style.display = privacyCollapsed ? 'none' : '';
}
section.classList.remove('hidden');
}
let privacyCollapsed = false;
// The header + customer summary stay visible; only the findings table collapses.
let privacyCollapsed = true;
function togglePrivacy() {
const body = document.getElementById('privacy-body');
const box = document.getElementById('privacy-findings');
const toggle = document.getElementById('privacy-toggle');
if (!body) return;
if (!box || !document.getElementById('privacy-rows').children.length) return;
privacyCollapsed = !privacyCollapsed;
body.style.display = privacyCollapsed ? 'none' : '';
box.style.display = privacyCollapsed ? 'none' : '';
toggle.textContent = privacyCollapsed ? '▼' : '▲';
}
@@ -1621,11 +1635,11 @@ async function clearData() {
if (privacyRows) privacyRows.innerHTML = '';
const privacyCustomer = document.getElementById('privacy-customer');
if (privacyCustomer) privacyCustomer.innerHTML = '';
privacyCollapsed = false;
const privacyBody = document.getElementById('privacy-body');
if (privacyBody) privacyBody.style.display = '';
privacyCollapsed = true;
const privacyFindings = document.getElementById('privacy-findings');
if (privacyFindings) privacyFindings.style.display = 'none';
const privacyToggle = document.getElementById('privacy-toggle');
if (privacyToggle) privacyToggle.textContent = '';
if (privacyToggle) { privacyToggle.textContent = ''; privacyToggle.style.visibility = ''; }
} catch (err) {
console.error('Failed to clear data:', err);
}
+23 -21
View File
@@ -159,6 +159,29 @@
</section>
<section id="data-section" class="hidden">
<section id="privacy-section" class="parse-errors-section hidden">
<div class="parse-errors-header" onclick="togglePrivacy()">
<span id="privacy-title">Customer data</span>
<span id="privacy-toggle" class="parse-errors-toggle"></span>
</div>
<div id="privacy-body" class="parse-errors-body">
<div id="privacy-customer" class="privacy-customer"></div>
<div id="privacy-findings" class="privacy-findings" style="display:none">
<table class="parse-errors-table">
<thead>
<tr>
<th>Severity</th>
<th>Category</th>
<th>Location</th>
<th>Match</th>
<th>Hint</th>
</tr>
</thead>
<tbody id="privacy-rows"></tbody>
</table>
</div>
</div>
</section>
<section class="viewer-panel">
<div class="audit-viewer-shell">
<iframe
@@ -190,27 +213,6 @@
</table>
</div>
</section>
<section id="privacy-section" class="parse-errors-section hidden">
<div class="parse-errors-header" onclick="togglePrivacy()">
<span id="privacy-title">Customer data</span>
<span id="privacy-toggle" class="parse-errors-toggle"></span>
</div>
<div id="privacy-body" class="parse-errors-body">
<div id="privacy-customer" class="privacy-customer"></div>
<table class="parse-errors-table">
<thead>
<tr>
<th>Severity</th>
<th>Category</th>
<th>Location</th>
<th>Match</th>
<th>Hint</th>
</tr>
</thead>
<tbody id="privacy-rows"></tbody>
</table>
</div>
</section>
</section>
</main>