codeSentry / codesentry-frontend /src /components /AMDMigrationPanel.jsx
YashashviAlva's picture
Initial commit for HF Spaces deploy
7b4f5dd
/* ═══════════════════════════════════════════════════════════════
AMDMigrationPanel β€” CUDA β†’ ROCm Migration Advisor
Shows compatibility score + per-finding migration guidance
═══════════════════════════════════════════════════════════════ */
import { useState } from 'react';
import './AMDMigrationPanel.css';
function ScoreCircle({ score }) {
const radius = 58;
const circumference = 2 * Math.PI * radius;
const offset = circumference - (score / 100) * circumference;
let colorClass = 'score-red';
let strokeClass = 'stroke-red';
if (score >= 90) { colorClass = 'score-green'; strokeClass = 'stroke-green'; }
else if (score >= 70) { colorClass = 'score-yellow'; strokeClass = 'stroke-yellow'; }
else if (score >= 50) { colorClass = 'score-orange'; strokeClass = 'stroke-orange'; }
return (
<div className="amd-score-circle">
<svg viewBox="0 0 140 140">
<circle className="amd-score-circle-bg" cx="70" cy="70" r={radius} />
<circle
className={`amd-score-circle-fill ${strokeClass}`}
cx="70"
cy="70"
r={radius}
strokeDasharray={circumference}
strokeDashoffset={offset}
/>
</svg>
<div className="amd-score-value">
<span className={`amd-score-number ${colorClass}`}>{score}</span>
<span className="amd-score-pct">%</span>
</div>
</div>
);
}
function MigrationFinding({ finding }) {
const [expanded, setExpanded] = useState(false);
const sevClass = `sev-${finding.severity}`;
return (
<div className="amd-mig-finding">
<div className="amd-mig-finding-header" onClick={() => setExpanded(!expanded)}>
<span className={`amd-mig-sev-badge ${sevClass}`}>{finding.severity}</span>
<span className="amd-mig-finding-id">{finding.id}</span>
<span className="amd-mig-finding-title">{finding.title}</span>
<button className="amd-mig-expand-btn" aria-label="Toggle details">
{expanded ? 'β–Ύ' : 'β–Έ'}
</button>
</div>
{expanded && (
<div className="amd-mig-finding-detail">
{finding.file && (
<div className="amd-mig-file-loc">
<span>πŸ“„</span>
<span>{finding.file}{finding.line ? `:${finding.line}` : ''}</span>
</div>
)}
<p className="amd-mig-description">{finding.description}</p>
<div className="amd-mig-fix-section">
<div className="amd-mig-fix-label">πŸ”§ ROCm Fix</div>
<p className="amd-mig-fix-text">{finding.rocm_fix}</p>
</div>
</div>
)}
</div>
);
}
export default function AMDMigrationPanel({ migrationData }) {
if (!migrationData) return null;
const {
compatibility_score = 100,
compatibility_label = 'Fully ROCm Ready',
findings = [],
total_cuda_patterns_found = 0,
summary = '',
} = migrationData;
let labelColor = 'score-red';
if (compatibility_score >= 90) labelColor = 'score-green';
else if (compatibility_score >= 70) labelColor = 'score-yellow';
else if (compatibility_score >= 50) labelColor = 'score-orange';
const handleExport = () => {
let md = `# AMD ROCm Migration Guide β€” CodeSentry\n\n`;
md += `## Compatibility Score: ${compatibility_score}% β€” ${compatibility_label}\n\n`;
md += `## Found ${total_cuda_patterns_found} CUDA-Specific Pattern(s)\n\n`;
if (summary) {
md += `> ${summary}\n\n`;
}
md += `---\n\n`;
findings.forEach((f) => {
md += `### ${f.id}: ${f.title}\n\n`;
md += `**Severity:** ${f.severity.toUpperCase()}\n\n`;
if (f.file) {
md += `**File:** \`${f.file}${f.line ? ':' + f.line : ''}\`\n\n`;
}
md += `**Issue:** ${f.description}\n\n`;
md += `**ROCm Fix:** ${f.rocm_fix}\n\n`;
if (f.code_snippet) {
md += `**Code:**\n\`\`\`python\n${f.code_snippet}\n\`\`\`\n\n`;
}
md += `---\n\n`;
});
md += `\n*Generated by CodeSentry AMD Migration Advisor*\n`;
const blob = new Blob([md], { type: 'text/markdown' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'AMD_MIGRATION_GUIDE.md';
a.click();
URL.revokeObjectURL(url);
};
return (
<div className="amd-migration-panel" id="amd-migration-panel">
{/* Header */}
<div className="amd-mig-header">
<span style={{ fontSize: '1.4rem' }}>πŸ”΄</span>
<h3>AMD ROCm Migration Advisor</h3>
</div>
{/* Score */}
<div className="amd-score-section">
<ScoreCircle score={compatibility_score} />
<span className={`amd-score-label ${labelColor}`}>{compatibility_label}</span>
</div>
{/* Findings */}
{findings.length > 0 ? (
<div className="amd-mig-findings">
{findings.map((f, idx) => (
<MigrationFinding key={`${f.id}-${idx}`} finding={f} />
))}
</div>
) : (
<div className="amd-no-findings">
βœ… No CUDA-specific patterns detected
<div className="amd-no-findings-sub">This codebase is fully AMD ROCm compatible</div>
</div>
)}
{/* Footer */}
<div className="amd-mig-footer">
<button className="btn btn-secondary btn-sm" onClick={handleExport} style={{ marginBottom: '8px' }}>
πŸ”΄ Export AMD Migration Guide
</button>
<div className="amd-mig-footer-text">
{total_cuda_patterns_found > 0
? `Apply all AMD fixes β†’ Generate ROCm-optimized patch`
: `Codebase verified for AMD MI300X deployment`}
</div>
</div>
</div>
);
}