async function renderLearningAnalytics() { const content = document.getElementById('pageContent'); content.innerHTML = `
Skill Scores
Score Trends
Skill Details
`; try { const [skillData, trendData] = await Promise.all([api.getSkillAnalytics(), api.getTrendAnalytics()]); const skills = skillData.skills || []; const trends = trendData.trends || {}; const grid = document.getElementById('skillScoresGrid'); if (grid) { if (skills.length === 0) { grid.innerHTML = `
๐Ÿ“Š
No skill data yet
Skill evaluations will appear here as they accumulate
`; } else { const topSkills = skills.sort((a, b) => (b.score || 0) - (a.score || 0)).slice(0, 6); grid.innerHTML = topSkills.map(s => { const pct = Math.round((s.score || 0) * 100); return `
${escapeHtml(s.name)}
${s.evals || 0} evaluations
${pct}%
`; }).join(''); } } const trendSection = document.getElementById('trendCharts'); if (trendSection) { const trendEntries = Object.entries(trends).slice(0, 4); if (trendEntries.length === 0) { trendSection.innerHTML = `
๐Ÿ“ˆ
No trend data
Trends will appear after multiple evaluations
`; } else { trendSection.innerHTML = trendEntries.map(([name, history]) => { const vals = (history || []).slice(-10); const maxVal = Math.max(...vals, 0.01); const chartHeight = 120; return `
${escapeHtml(name)}
${vals.map((v, i) => { const h = (v / maxVal) * (chartHeight - 25); return `
`; }).join('')}
${vals.length} data points Avg: ${(vals.reduce((a, b) => a + b, 0) / vals.length * 100).toFixed(0)}%
`; }).join(''); } } const details = document.getElementById('skillDetailsList'); if (details) { if (skills.length === 0) { details.innerHTML = ''; } else { details.innerHTML = skills.map(s => { const pct = Math.round((s.score || 0) * 100); return `
${escapeHtml(s.name)}
${s.evals || 0} evaluations ยท Best: ${((s.best || 0) * 100).toFixed(0)}%
${pct}%
`; }).join(''); } } } catch (err) { showToast('Failed to load analytics: ' + err.message, 'error'); } }