Files
PR-Helper/static/js/review-inline.js
T

127 lines
4.6 KiB
JavaScript

// Review Inline: renders AI review suggestions inline in a diff view
const ReviewInline = {
suggestions: [],
init(diffContainerId, suggestionsContainerId) {
this.diffContainer = document.getElementById(diffContainerId);
this.suggestionsContainer = document.getElementById(suggestionsContainerId);
this.suggestions = [];
},
// Add a suggestion to the collection
addSuggestion(suggestion) {
this.suggestions.push(suggestion);
},
// Render all collected suggestions inline in the diff
renderInline() {
if (!this.diffContainer) return;
this.suggestions.forEach((s, index) => {
DiffViewer.insertSuggestion(
s.file,
s.line,
s.side || 'right',
s.severity || 'info',
s.content || '',
`suggestion-${index}`
);
});
},
// Render a single suggestion card (for the card-based view)
renderSuggestionCard(suggestion) {
const severityStyles = {
critical: {
border: 'border-l-4 border-red-500',
bg: 'bg-red-50',
badge: 'bg-red-100 text-red-800',
icon: '🔴',
label: '严重',
},
warning: {
border: 'border-l-4 border-yellow-500',
bg: 'bg-yellow-50',
badge: 'bg-yellow-100 text-yellow-800',
icon: '🟡',
label: '建议',
},
info: {
border: 'border-l-4 border-green-500',
bg: 'bg-green-50',
badge: 'bg-green-100 text-green-800',
icon: '🟢',
label: '提示',
},
};
const style = severityStyles[suggestion.severity] || severityStyles.info;
return `
<div class="review-card ${style.border} ${style.bg} rounded-lg p-4 mb-3">
<div class="flex items-center gap-2 mb-2">
<span class="${style.badge} px-2 py-0.5 rounded text-xs font-medium">
${style.icon} ${style.label}
</span>
${suggestion.file ? `<span class="text-xs text-gray-500 font-mono">${suggestion.file}</span>` : ''}
${suggestion.line ? `<span class="text-xs text-gray-400">行 ${suggestion.line}</span>` : ''}
</div>
<div class="text-sm text-gray-700 review-content">${typeof renderMarkdown === 'function' ? renderMarkdown(suggestion.content || '') : (suggestion.content || '')}</div>
${suggestion.code_example ? `
<pre class="mt-2 p-2 bg-gray-100 rounded text-xs overflow-x-auto"><code>${this._escapeHtml(suggestion.code_example)}</code></pre>
` : ''}
</div>`;
},
// Render file review section
renderFileReview(fileReview) {
const severityOrder = { critical: 0, warning: 1, info: 2 };
const suggestions = (fileReview.suggestions || []).sort((a, b) =>
(severityOrder[a.severity] || 2) - (severityOrder[b.severity] || 2)
);
const maxSeverity = suggestions.length > 0 ? suggestions[0].severity : 'info';
const severityColors = {
critical: 'border-red-500',
warning: 'border-yellow-500',
info: 'border-green-500',
};
let html = `
<div class="file-review bg-white rounded-lg shadow-md ${severityColors[maxSeverity] || ''} border-l-4 mb-4">
<div class="p-4 border-b border-gray-100">
<h3 class="font-medium text-gray-900 font-mono text-sm">${fileReview.filename || ''}</h3>
${fileReview.summary ? `<p class="text-sm text-gray-600 mt-1">${fileReview.summary}</p>` : ''}
</div>
<div class="p-4 space-y-3">`;
suggestions.forEach(s => {
html += this.renderSuggestionCard(s);
});
html += `
</div>
</div>`;
return html;
},
// Render overall summary
renderSummary(summary) {
if (!summary) return '';
return `
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
<h2 class="text-lg font-semibold text-gray-900 mb-3">整体评估</h2>
<div class="prose text-sm text-gray-700">${summary}</div>
</div>`;
},
_escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
};
window.ReviewInline = ReviewInline;