codeflash-internal/experiments/code_repair_dashboard.html
Aseem Saxena 1192df12a6
feedback loop for unmatched test results (#2059)
fixes CF-932

# Pull Request Checklist

## Description
- [ ] **Description of PR**: Clear and concise description of what this
PR accomplishes
- [ ] **Breaking Changes**: Document any breaking changes (if
applicable)
- [ ] **Related Issues**: Link to any related issues or tickets

## Testing
- [ ] **Test cases Attached**: All relevant test cases have been
added/updated
- [ ] **Manual Testing**: Manual testing completed for the changes

## Monitoring & Debugging
- [ ] **Logging in place**: Appropriate logging has been added for
debugging user issues
- [ ] **Sentry will be able to catch errors**: Error handling ensures
Sentry can capture and report errors
- [ ] **Avoid Dev based/Prisma logging**: No development-only or
Prisma-specific logging in production code

## Configuration
- [ ] **Env variables newly added**: Any new environment variables are
documented in .env.example file or mentioned in description
---

## Additional Notes
<!-- Add any additional context, screenshots, or notes for reviewers
here -->

---------

Co-authored-by: codeflash-ai[bot] <148906541+codeflash-ai[bot]@users.noreply.github.com>
Co-authored-by: ali <mohammed18200118@gmail.com>
Co-authored-by: Kevin Turcios <106575910+KRRT7@users.noreply.github.com>
2025-12-17 08:14:32 +05:30

475 lines
16 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Code Repair Logs Dashboard</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background: #1a1a2e;
color: #eee;
min-height: 100vh;
padding: 20px;
}
h1 {
text-align: center;
margin-bottom: 20px;
color: #00d9ff;
}
.stats {
display: flex;
gap: 20px;
justify-content: center;
margin-bottom: 30px;
flex-wrap: wrap;
}
.stat-card {
background: #16213e;
padding: 20px 30px;
border-radius: 10px;
text-align: center;
min-width: 150px;
}
.stat-card .number {
font-size: 2em;
font-weight: bold;
color: #00d9ff;
}
.stat-card .label {
color: #888;
font-size: 0.9em;
}
.search-bar {
display: flex;
gap: 10px;
margin-bottom: 20px;
justify-content: center;
flex-wrap: wrap;
}
.search-bar input {
padding: 10px 15px;
border: none;
border-radius: 5px;
background: #16213e;
color: #eee;
width: 300px;
font-size: 1em;
}
.search-bar input:focus {
outline: 2px solid #00d9ff;
}
.trace-group {
background: #16213e;
border-radius: 10px;
margin-bottom: 20px;
overflow: hidden;
}
.trace-header {
background: #0f3460;
padding: 15px 20px;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
transition: background 0.2s;
}
.trace-header:hover {
background: #1a4a80;
}
.trace-header .trace-id {
font-family: monospace;
color: #00d9ff;
font-size: 0.95em;
}
.trace-header .count-badge {
background: #e94560;
color: white;
padding: 3px 10px;
border-radius: 15px;
font-size: 0.85em;
}
.trace-header .arrow {
transition: transform 0.2s;
}
.trace-header.expanded .arrow {
transform: rotate(180deg);
}
.trace-content {
display: none;
padding: 0;
}
.trace-content.show {
display: block;
}
.log-entry {
border-top: 1px solid #0f3460;
padding: 20px;
}
.log-entry:first-child {
border-top: none;
}
.log-entry-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
flex-wrap: wrap;
gap: 10px;
}
.optimization-id {
font-family: monospace;
font-size: 0.8em;
color: #888;
}
.timestamp {
font-size: 0.8em;
color: #888;
}
.section {
margin-bottom: 15px;
}
.section-title {
font-weight: bold;
color: #00d9ff;
margin-bottom: 8px;
font-size: 0.9em;
text-transform: uppercase;
}
.code-block {
background: #0d1117;
border-radius: 5px;
padding: 15px;
overflow-x: auto;
font-family: 'Fira Code', 'Consolas', monospace;
font-size: 0.85em;
line-height: 1.5;
white-space: pre-wrap;
word-wrap: break-word;
max-height: 400px;
overflow-y: auto;
}
.explanation-block {
background: #1e3a5f;
border-radius: 5px;
padding: 15px;
line-height: 1.6;
font-size: 0.9em;
max-height: 300px;
overflow-y: auto;
}
.refined-code {
background: #0d2818;
border: 1px solid #2ea043;
}
.expand-all-btn {
background: #0f3460;
color: #eee;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
font-size: 0.9em;
transition: background 0.2s;
}
.expand-all-btn:hover {
background: #1a4a80;
}
.no-results {
text-align: center;
padding: 40px;
color: #888;
}
.copy-btn {
background: #333;
color: #888;
border: none;
padding: 5px 10px;
border-radius: 3px;
cursor: pointer;
font-size: 0.75em;
float: right;
margin-bottom: 5px;
}
.copy-btn:hover {
background: #444;
color: #eee;
}
.status-badges {
display: flex;
gap: 8px;
margin-top: 10px;
}
.status-badge {
padding: 4px 12px;
border-radius: 4px;
font-size: 0.8em;
font-weight: 600;
text-transform: uppercase;
}
.status-badge.passed-true {
background: #238636;
color: #fff;
}
.status-badge.passed-false {
background: #da3633;
color: #fff;
}
.status-badge.faster-true {
background: #1f6feb;
color: #fff;
}
.status-badge.faster-false {
background: #6e7681;
color: #fff;
}
.status-badge.pending {
background: #484f58;
color: #8b949e;
}
.trace-status-summary {
display: flex;
gap: 8px;
align-items: center;
}
.trace-status-icon {
font-size: 1.1em;
}
</style>
</head>
<body>
<h1>Code Repair Logs Dashboard</h1>
<div class="stats">
<div class="stat-card">
<div class="number" id="total-traces">0</div>
<div class="label">Trace Groups</div>
</div>
<div class="stat-card">
<div class="number" id="total-logs">0</div>
<div class="label">Total Logs</div>
</div>
<div class="stat-card">
<div class="number" id="avg-per-trace">0</div>
<div class="label">Avg per Trace</div>
</div>
<div class="stat-card">
<div class="number" id="passed-count" style="color: #238636;">0</div>
<div class="label">Passed</div>
</div>
<div class="stat-card">
<div class="number" id="faster-count" style="color: #1f6feb;">0</div>
<div class="label">Faster</div>
</div>
</div>
<div class="search-bar">
<input type="text" id="search" placeholder="Search by trace ID, optimization ID, or content...">
<button class="expand-all-btn" onclick="toggleAll()">Expand All</button>
</div>
<div id="dashboard"></div>
<script>
// Data will be injected here
const data = DATA_PLACEHOLDER;
let allExpanded = false;
function escapeHtml(text) {
if (!text) return '';
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function formatDate(dateStr) {
if (!dateStr) return '';
const date = new Date(dateStr);
return date.toLocaleString();
}
function copyToClipboard(text, btn) {
navigator.clipboard.writeText(text).then(() => {
const originalText = btn.textContent;
btn.textContent = 'Copied!';
setTimeout(() => btn.textContent = originalText, 1500);
});
}
function getStatusBadge(value, label, type) {
if (value === null || value === undefined) {
return `<span class="status-badge pending">${label}: Pending</span>`;
}
const isTrue = value === 'True' || value === 'true' || value === true || value === 'yes';
const className = `${type}-${isTrue}`;
const displayValue = isTrue ? 'Yes' : 'No';
return `<span class="status-badge ${className}">${label}: ${displayValue}</span>`;
}
function getTraceStatusSummary(logs) {
const withStatus = logs.filter(l => l.passed !== null && l.passed !== undefined);
if (withStatus.length === 0) return '';
const passedCount = withStatus.filter(l => l.passed === 'True' || l.passed === 'true' || l.passed === true).length;
const fasterCount = withStatus.filter(l => l.faster === 'True' || l.faster === 'true' || l.faster === true).length;
const passedIcon = passedCount === withStatus.length ? '✓' : passedCount > 0 ? '◐' : '✗';
const fasterIcon = fasterCount === withStatus.length ? '⚡' : fasterCount > 0 ? '◐' : '';
return `<span class="trace-status-summary">
<span title="Passed: ${passedCount}/${withStatus.length}">${passedIcon}</span>
<span title="Faster: ${fasterCount}/${withStatus.length}">${fasterIcon}</span>
</span>`;
}
function renderDashboard(filteredData = data) {
const dashboard = document.getElementById('dashboard');
// Group by trace_id
const grouped = {};
filteredData.forEach(log => {
if (!grouped[log.trace_id]) {
grouped[log.trace_id] = [];
}
grouped[log.trace_id].push(log);
});
// Sort groups by most recent
const sortedTraces = Object.entries(grouped).sort((a, b) => {
const aDate = new Date(a[1][0].created_at);
const bDate = new Date(b[1][0].created_at);
return bDate - aDate;
});
// Update stats
document.getElementById('total-traces').textContent = sortedTraces.length;
document.getElementById('total-logs').textContent = filteredData.length;
document.getElementById('avg-per-trace').textContent = sortedTraces.length > 0
? (filteredData.length / sortedTraces.length).toFixed(1)
: '0';
// Calculate passed/faster stats
const withStatus = filteredData.filter(l => l.passed !== null && l.passed !== undefined);
const passedCount = withStatus.filter(l => l.passed === 'True' || l.passed === 'true' || l.passed === true).length;
const fasterCount = withStatus.filter(l => l.faster === 'True' || l.faster === 'true' || l.faster === true).length;
document.getElementById('passed-count').textContent = withStatus.length > 0 ? `${passedCount}/${withStatus.length}` : '';
document.getElementById('faster-count').textContent = withStatus.length > 0 ? `${fasterCount}/${withStatus.length}` : '';
if (sortedTraces.length === 0) {
dashboard.innerHTML = '<div class="no-results">No results found</div>';
return;
}
let html = '';
sortedTraces.forEach(([traceId, logs], idx) => {
// Sort logs within group by created_at
logs.sort((a, b) => new Date(a.created_at) - new Date(b.created_at));
html += `
<div class="trace-group">
<div class="trace-header" onclick="toggleTrace(${idx})">
<span class="trace-id">Trace: ${escapeHtml(traceId)}</span>
<div style="display: flex; align-items: center; gap: 10px;">
${getTraceStatusSummary(logs)}
<span class="count-badge">${logs.length} entries</span>
<span class="arrow">▼</span>
</div>
</div>
<div class="trace-content" id="trace-${idx}">
${logs.map((log, logIdx) => `
<div class="log-entry">
<div class="log-entry-header">
<span class="optimization-id">Optimization: ${escapeHtml(log.optimization_id)}</span>
<span class="timestamp">${formatDate(log.created_at)}</span>
</div>
<div class="status-badges">
${getStatusBadge(log.passed, 'Passed', 'passed')}
${getStatusBadge(log.faster, 'Faster', 'faster')}
</div>
<div class="section" style="margin-top: 15px;">
<div class="section-title">User Prompt</div>
<button class="copy-btn" onclick="copyToClipboard(data.find(d => d.optimization_id === '${log.optimization_id}').user_prompt, this)">Copy</button>
<div class="code-block">${escapeHtml(log.user_prompt)}</div>
</div>
<div class="section">
<div class="section-title">Explanation</div>
<div class="explanation-block">${escapeHtml(log.explanation)}</div>
</div>
<div class="section">
<div class="section-title">Refined Optimization</div>
<button class="copy-btn" onclick="copyToClipboard(data.find(d => d.optimization_id === '${log.optimization_id}').refined_optimization, this)">Copy</button>
<div class="code-block refined-code">${escapeHtml(log.refined_optimization)}</div>
</div>
</div>
`).join('')}
</div>
</div>`;
});
dashboard.innerHTML = html;
}
function toggleTrace(idx) {
const content = document.getElementById(`trace-${idx}`);
const header = content.previousElementSibling;
content.classList.toggle('show');
header.classList.toggle('expanded');
}
function toggleAll() {
const contents = document.querySelectorAll('.trace-content');
const headers = document.querySelectorAll('.trace-header');
allExpanded = !allExpanded;
contents.forEach(c => {
if (allExpanded) {
c.classList.add('show');
} else {
c.classList.remove('show');
}
});
headers.forEach(h => {
if (allExpanded) {
h.classList.add('expanded');
} else {
h.classList.remove('expanded');
}
});
document.querySelector('.expand-all-btn').textContent = allExpanded ? 'Collapse All' : 'Expand All';
}
document.getElementById('search').addEventListener('input', function(e) {
const query = e.target.value.toLowerCase();
if (!query) {
renderDashboard(data);
return;
}
const filtered = data.filter(log =>
(log.trace_id && log.trace_id.toLowerCase().includes(query)) ||
(log.optimization_id && log.optimization_id.toLowerCase().includes(query)) ||
(log.user_prompt && log.user_prompt.toLowerCase().includes(query)) ||
(log.explanation && log.explanation.toLowerCase().includes(query)) ||
(log.refined_optimization && log.refined_optimization.toLowerCase().includes(query))
);
renderDashboard(filtered);
});
// Initial render
renderDashboard();
</script>
</body>
</html>