Fixed broken "Decisions Over Time" chart that wasn't displaying bars. Root cause: Empty divs with percentage heights collapsed in flex containers. Fixes applied: 1. **Pixel heights instead of percentages** - Calculate absolute pixel heights from h-48 container (192px) - Percentage heights don't work in flex containers with items-end 2. **Non-breaking space inside bars** - Added to prevent empty div collapse - Even with height set, empty divs can collapse in some layouts 3. **Decision count labels** - Display count above each bar for exact numbers - Shows both visual proportion (bar height) and exact value (label) 4. **Minimum 10px height** - Ensures small values are always visible - Prevents bars from disappearing for low counts 5. **Wider bars** - Changed from max-w-16 (64px) to w-3/4 (75% width) - More visible and easier to interact with Timeline modes working: - ✅ 6-Hourly (24h) - 4 bars showing last 24 hours in 6-hour buckets - ✅ Daily (7d) - 7 bars showing last 7 days - ✅ Weekly (4w) - 4 bars showing last 4 weeks All modes show current snapshot updated on refresh. Files changed: - public/js/admin/audit-analytics.js: Timeline rendering logic - public/admin/audit-analytics.html: Updated cache version - public/*.html: Cache version bump for consistency 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
219 lines
9.6 KiB
HTML
219 lines
9.6 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Audit Analytics | Tractatus Admin</title>
|
|
<link rel="icon" type="image/svg+xml" href="/favicon-new.svg">
|
|
<link rel="stylesheet" href="/css/tailwind.css?v=0.1.0.1761262254119">
|
|
<link rel="stylesheet" href="/css/tractatus-theme.min.css?v=0.1.0.1761262254119">
|
|
<script src="/js/admin/auth-check.js?v=0.1.0.1761262254119"></script>
|
|
<style>
|
|
html { scroll-behavior: smooth; }
|
|
|
|
.metric-card {
|
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
}
|
|
|
|
.metric-card:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.chart-container {
|
|
position: relative;
|
|
height: 300px;
|
|
}
|
|
|
|
.log-entry {
|
|
transition: background-color 0.2s ease;
|
|
}
|
|
|
|
.log-entry:hover {
|
|
background-color: #f3f4f6;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="bg-gray-50">
|
|
|
|
<!-- Navigation -->
|
|
<div id="admin-navbar" data-page-title="Audit Analytics" data-page-icon="analytics"></div>
|
|
<script src="/js/components/navbar-admin.js?v=0.1.0.1761262254119"></script>
|
|
|
|
<!-- Page Header -->
|
|
<div class="bg-white border-b border-gray-200">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h1 class="text-3xl font-bold text-gray-900">Audit Analytics</h1>
|
|
<p class="text-gray-600 mt-2">Governance decision monitoring and insights</p>
|
|
</div>
|
|
<div class="flex items-center gap-4">
|
|
<button id="refresh-btn" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition">
|
|
<svg class="w-5 h-5 inline-block mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
|
|
</svg>
|
|
Refresh
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Main Content -->
|
|
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
|
|
<!-- Summary Cards -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
|
<!-- Total Decisions -->
|
|
<div class="metric-card bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-sm text-gray-600 font-medium">Total Decisions</p>
|
|
<p id="total-decisions" class="text-3xl font-bold text-gray-900 mt-2">-</p>
|
|
</div>
|
|
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center">
|
|
<svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Allowed Rate -->
|
|
<div class="metric-card bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-sm text-gray-600 font-medium">Allowed Rate</p>
|
|
<p id="allowed-rate" class="text-3xl font-bold text-green-600 mt-2">-</p>
|
|
</div>
|
|
<div class="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center">
|
|
<svg class="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Violations -->
|
|
<div class="metric-card bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-sm text-gray-600 font-medium">Violations</p>
|
|
<p id="violations-count" class="text-3xl font-bold text-red-600 mt-2">-</p>
|
|
</div>
|
|
<div class="w-12 h-12 bg-red-100 rounded-lg flex items-center justify-center">
|
|
<svg class="w-6 h-6 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Services Active -->
|
|
<div class="metric-card bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-sm text-gray-600 font-medium">Services Active</p>
|
|
<p id="services-count" class="text-3xl font-bold text-purple-600 mt-2">-</p>
|
|
</div>
|
|
<div class="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center">
|
|
<svg class="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"/>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Charts Row -->
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
|
|
<!-- Decisions by Action Type -->
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">Decisions by Action Type</h3>
|
|
<div id="action-chart" class="chart-container">
|
|
<!-- Chart will be rendered here -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Decisions by Service -->
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">Decisions by Framework Service</h3>
|
|
<div id="service-chart" class="chart-container">
|
|
<!-- Chart will be rendered here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Service Health (24h) -->
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">Service Health (Last 24 Hours)</h3>
|
|
<div id="service-health-24h" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
<!-- Will be populated by JS -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Violations & Blocks (7 days) -->
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mb-8">
|
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">Violations & Blocks (Last 7 Days)</h3>
|
|
<div id="violations-7days" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
|
<!-- Will be populated by JS -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Timeline Chart -->
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mb-8">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h3 class="text-lg font-semibold text-gray-900">Decisions Over Time</h3>
|
|
<div class="flex gap-2">
|
|
<button data-timeline-mode="6hourly" data-action="switchTimelineMode" data-arg0="6hourly"
|
|
class="px-3 py-1 text-sm rounded bg-gray-200 text-gray-700 hover:bg-gray-300 transition">
|
|
6-Hourly (24h)
|
|
</button>
|
|
<button data-timeline-mode="daily" data-action="switchTimelineMode" data-arg0="daily"
|
|
class="px-3 py-1 text-sm rounded bg-purple-600 text-white hover:bg-purple-700 transition">
|
|
Daily (7d)
|
|
</button>
|
|
<button data-timeline-mode="weekly" data-action="switchTimelineMode" data-arg0="weekly"
|
|
class="px-3 py-1 text-sm rounded bg-gray-200 text-gray-700 hover:bg-gray-300 transition">
|
|
Weekly (4w)
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="timeline-chart" class="chart-container">
|
|
<!-- Chart will be rendered here -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Decisions -->
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200">
|
|
<div class="p-6 border-b border-gray-200">
|
|
<h3 class="text-lg font-semibold text-gray-900">Recent Decisions (Last 10)</h3>
|
|
</div>
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full divide-y divide-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Timestamp</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Action</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Session</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Violations</th>
|
|
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Details</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="audit-log-tbody" class="bg-white divide-y divide-gray-200">
|
|
<tr>
|
|
<td colspan="6" class="px-6 py-4 text-center text-gray-500">Loading...</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
</main>
|
|
|
|
<script src="/js/admin/audit-analytics.js?v=0.1.0.1761348045814"></script>
|
|
|
|
</body>
|
|
</html>
|