Files
logpile/web/templates/index.html
T
Mikhail ChusavitinandClaude Sonnet 5 95f552a0e5 feat(privacy): fold sanitize into the header "Remove personal data" button
Drops the in-panel sanitize sub-block (button + preview table + "already
sanitized" note) that duplicated affordances across the page. The header
"Clear Data" button is renamed "Remove personal data" and now sanitizes the
uploaded file and downloads the clean copy in one click - no preview, no
confirmation. It is shown only when the source can be sanitized, and reads
"Personal data removed" (disabled) when the file already looks de-identified.
The old clearData() teardown is covered by Restart.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 10:19:44 +03:00

228 lines
12 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LOGPile - BMC Log Analyzer</title>
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<header class="page-header">
<div class="page-header-brand">
<p class="page-eyebrow">Diagnostic Workbench</p>
<h1>LOGPile</h1>
<p class="page-subtitle">BMC diagnostic data analyzer</p>
</div>
<div id="header-log-meta" class="header-log-meta hidden">
<div class="header-actions">
<button id="clear-btn" class="header-action hidden" onclick="removePersonalData()">Remove personal data</button>
<button id="header-raw-btn" class="header-action hidden" onclick="exportData('json')">Raw Data</button>
<button id="header-reanimator-btn" class="header-action hidden" onclick="exportData('reanimator')">Reanimator</button>
<button id="header-logs-csv-btn" class="header-action hidden" onclick="exportData('logs-csv')">Logs Export</button>
<button id="restart-btn" class="header-action" onclick="restartApp()">Restart</button>
<button id="exit-btn" class="header-action" onclick="exitApp()">Exit</button>
</div>
</div>
</header>
<main class="page-main">
<section id="upload-section" class="control-deck">
<div class="source-switch" role="tablist" aria-label="Data source">
<button type="button" class="source-switch-btn active" data-source-type="archive">Archive</button>
<button type="button" class="source-switch-btn" data-source-type="api">API</button>
<button type="button" class="source-switch-btn" data-source-type="convert">Convert</button>
</div>
<div id="archive-source-content" class="surface-panel upload-panel">
<h2>Open Archive</h2>
<p>Upload a support archive, plain log, or raw JSON snapshot to open the hardware report.</p>
<div class="upload-area upload-dropzone" id="drop-zone">
<input type="file" id="file-input" accept="application/gzip,application/x-gzip,application/x-tar,application/zip,application/json,text/plain,.ahs,.json,.tar,.tar.gz,.tgz,.sds,.zip,.txt,.log" hidden>
<span class="upload-kicker">Archive Import</span>
<strong>Drop a file here</strong>
<span class="upload-copy">LOGPile will parse it and open the report immediately.</span>
<div class="upload-actions">
<button type="button" onclick="document.getElementById('file-input').click()">Select File</button>
</div>
<p class="hint">Supported formats: `.ahs`, `.tar.gz`, `.tar`, `.tgz`, `.sds`, `.zip`, `.json`, `.txt`, `.log`</p>
</div>
<div id="upload-status"></div>
<div id="parsers-info" class="parsers-info"></div>
</div>
<div id="api-source-content" class="surface-panel upload-panel hidden">
<h2>BMC API</h2>
<p>Validate access and start live collection through the production Redfish pipeline.</p>
<form id="api-connect-form" novalidate>
<div id="api-form-errors" class="form-errors hidden"></div>
<div class="api-form-grid">
<label class="api-form-field" for="api-host">
<span>Host</span>
<input id="api-host" name="host" type="text" placeholder="10.0.0.10 or bmc.example.local">
<span class="field-error" data-error-for="host"></span>
</label>
<label class="api-form-field" for="api-port">
<span>Port</span>
<input id="api-port" name="port" type="number" min="1" max="65535" value="443" placeholder="443">
<span class="field-error" data-error-for="port"></span>
</label>
<label class="api-form-field" for="api-username">
<span>Username</span>
<input id="api-username" name="username" type="text" placeholder="admin">
<span class="field-error" data-error-for="username"></span>
</label>
<label class="api-form-field" id="api-password-field" for="api-password">
<span>Password</span>
<input id="api-password" name="password" type="password" autocomplete="current-password">
<span class="field-error" data-error-for="password"></span>
</label>
</div>
<div class="api-form-actions">
<button id="api-connect-btn" type="button">Connect</button>
</div>
<div id="api-connect-status" class="api-connect-status"></div>
<div id="api-probe-options" class="api-probe-options hidden">
<div id="api-host-off-warning" class="api-host-off-warning hidden">
&#9888; Host is powered off. Inventory data may be incomplete.
</div>
<label class="api-form-checkbox" for="api-debug-payloads">
<input id="api-debug-payloads" name="debug_payloads" type="checkbox">
<span>Collect extended diagnostics</span>
</label>
<div class="api-form-actions">
<button id="api-collect-btn" type="submit">Collect</button>
</div>
</div>
</form>
<section id="api-job-status" class="job-status hidden" aria-live="polite">
<div class="job-status-header">
<h4>Collection Job Status</h4>
<div class="job-status-actions">
<button id="skip-hung-btn" type="button" class="hidden" title="Abort hung requests and continue with analysis of collected data">Skip Hung Requests</button>
<button id="cancel-job-btn" type="button">Cancel</button>
</div>
</div>
<div class="job-status-meta">
<div><span class="meta-label">jobId:</span> <code id="job-id-value">-</code></div>
<div>
<span class="meta-label">Status:</span>
<span id="job-status-value" class="job-status-badge">Queued</span>
</div>
<div><span class="meta-label">Stage:</span> <span id="job-progress-value">Collecting data...</span></div>
<div><span class="meta-label">ETA:</span> <span id="job-eta-value">-</span></div>
</div>
<div class="job-progress" aria-label="Job progress">
<div id="job-progress-bar" class="job-progress-bar" style="width: 0%">0%</div>
</div>
<div id="job-active-modules" class="job-active-modules hidden">
<p class="meta-label">Active modules:</p>
<div id="job-active-modules-list" class="job-module-chips"></div>
</div>
<div id="job-debug-info" class="job-debug-info hidden">
<p class="meta-label">Redfish debug:</p>
<div id="job-debug-summary" class="job-debug-summary"></div>
<div id="job-phase-telemetry" class="job-phase-telemetry"></div>
</div>
<div class="job-status-logs">
<p class="meta-label">Step log:</p>
<ul id="job-logs-list"></ul>
</div>
</section>
</div>
<div id="convert-source-content" class="surface-panel upload-panel hidden">
<h2>Batch Convert</h2>
<p>Select a folder with supported files. A separate Reanimator export will be produced for each file.</p>
<div class="api-form-actions">
<input type="file" id="convert-folder-input" webkitdirectory directory multiple hidden>
<button id="convert-folder-btn" type="button" onclick="document.getElementById('convert-folder-input').click()">Choose Folder</button>
<button id="convert-run-btn" type="button">Convert to Reanimator</button>
</div>
<div id="convert-progress" class="convert-progress hidden" aria-live="polite">
<div class="convert-progress-meta">
<span id="convert-progress-label">Preparing...</span>
<span id="convert-progress-value">0%</span>
</div>
<div class="convert-progress-track">
<div id="convert-progress-bar" class="convert-progress-bar" style="width: 0%"></div>
</div>
</div>
<div id="convert-folder-summary" class="api-connect-status"></div>
<div id="convert-status" class="api-connect-status"></div>
</div>
</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
id="audit-viewer-frame"
class="audit-viewer-frame"
title="Hardware report"
loading="eager"
scrolling="no"
referrerpolicy="same-origin">
</iframe>
</div>
</section>
<section id="parse-errors-section" class="parse-errors-section hidden">
<div class="parse-errors-header" onclick="toggleParseErrors()">
<span id="parse-errors-title">Collection warnings</span>
<span id="parse-errors-toggle" class="parse-errors-toggle"></span>
</div>
<div id="parse-errors-body" class="parse-errors-body">
<table class="parse-errors-table">
<thead>
<tr>
<th>Source</th>
<th>Section</th>
<th>Message</th>
<th>Detail</th>
</tr>
</thead>
<tbody id="parse-errors-rows"></tbody>
</table>
</div>
</section>
</section>
</main>
<footer class="page-footer">
<div class="footer-info">
<p>{{if .AppVersion}}LOGPile {{.AppVersion}}{{end}}{{if and .AppVersion .ChartVersion}} · {{end}}{{if .ChartVersion}}Chart {{.ChartVersion}}{{end}}</p>
</div>
</footer>
<script src="/static/js/app.js"></script>
</body>
</html>