200 lines
6.9 KiB
JavaScript
200 lines
6.9 KiB
JavaScript
let historyChart = null;
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
fetchQuotas();
|
|
fetchHistory();
|
|
setupThemeDropdown();
|
|
});
|
|
|
|
function setupThemeDropdown() {
|
|
const dropdown = document.getElementById('theme-dropdown');
|
|
dropdown.addEventListener('change', (e) => {
|
|
// Change body class
|
|
document.body.className = e.target.value;
|
|
|
|
// Update chart colors if chart exists
|
|
if (historyChart) {
|
|
updateChartTheme(e.target.value);
|
|
}
|
|
});
|
|
}
|
|
|
|
async function fetchQuotas() {
|
|
try {
|
|
const response = await fetch('/api/quotas');
|
|
const quotas = await response.json();
|
|
|
|
// Mock data if DB is empty
|
|
const activeQuotas = quotas.length > 0 ? quotas : [
|
|
{ provider: 'Antigravity', used: 68240, total: 100000, percentage: 68.24 },
|
|
{ provider: 'POE', used: 33750, total: 75000, percentage: 45 },
|
|
{ provider: 'MiniMax', used: 60, total: 100, percentage: 60 }
|
|
];
|
|
|
|
activeQuotas.forEach(quota => {
|
|
updateRow(quota.provider.toLowerCase(), quota);
|
|
});
|
|
} catch (error) {
|
|
console.error('Error fetching quotas:', error);
|
|
}
|
|
}
|
|
|
|
function updateRow(providerId, quota) {
|
|
const fill = document.getElementById(`fill-${providerId}`);
|
|
const statusText = document.getElementById(`status-${providerId}`);
|
|
const percentText = document.getElementById(`percentage-${providerId}`);
|
|
|
|
if (!fill || !statusText || !percentText) return;
|
|
|
|
const percentage = quota.percentage;
|
|
fill.style.width = `${percentage}%`;
|
|
|
|
// Update percentage text
|
|
percentText.innerText = `${Math.round(percentage)}%`;
|
|
|
|
// Status coloring
|
|
percentText.className = 'percentage'; // reset
|
|
if (percentage > 90) {
|
|
percentText.classList.add('status-danger');
|
|
} else if (percentage > 70) {
|
|
percentText.classList.add('status-warn');
|
|
} else {
|
|
percentText.classList.add('status-good');
|
|
}
|
|
|
|
// Detail text
|
|
if (quota.provider.toLowerCase() === 'minimax' && quota.meta) {
|
|
const reset5h = new Date(quota.meta.intervalReset).toLocaleTimeString();
|
|
statusText.innerHTML = `5h: ${quota.meta.intervalUsed}% (Resets: ${reset5h})`;
|
|
} else if (quota.provider.toLowerCase() === 'antigravity' && quota.meta) {
|
|
statusText.innerHTML = `5h: ${quota.meta.intervalUsed}% (Resets: ${quota.meta.intervalResetStr})`;
|
|
} else {
|
|
statusText.innerText = `${(quota.used).toLocaleString()} / ${(quota.total).toLocaleString()}`;
|
|
}
|
|
|
|
if (percentage >= 100) {
|
|
confetti({
|
|
particleCount: 100,
|
|
spread: 70,
|
|
origin: { y: 0.6 }
|
|
});
|
|
statusText.innerText = 'LIMIT REACHED!';
|
|
statusText.style.color = 'var(--danger)';
|
|
}
|
|
}
|
|
|
|
async function fetchHistory() {
|
|
try {
|
|
const response = await fetch('/api/history');
|
|
const history = await response.json();
|
|
|
|
const labels = [...new Set(history.map(item => new Date(item.timestamp).toLocaleTimeString()))].sort();
|
|
|
|
const antigravityData = history.filter(item => item.provider === 'Antigravity').map(item => item.percentage);
|
|
const poeData = history.filter(item => item.provider === 'POE').map(item => item.percentage);
|
|
const minimaxData = history.filter(item => item.provider === 'MiniMax').map(item => item.percentage);
|
|
|
|
const ctx = document.getElementById('historyChart').getContext('2d');
|
|
|
|
historyChart = new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: labels.length ? labels : ['10:00', '11:00', '12:00', '13:00'],
|
|
datasets: [
|
|
{
|
|
label: 'Antigravity (%)',
|
|
data: antigravityData.length ? antigravityData : [10, 30, 50, 68],
|
|
borderColor: '#58a6ff',
|
|
backgroundColor: 'rgba(88, 166, 255, 0.1)',
|
|
borderWidth: 2,
|
|
tension: 0.3,
|
|
fill: true
|
|
},
|
|
{
|
|
label: 'POE (%)',
|
|
data: poeData.length ? poeData : [5, 10, 20, 45],
|
|
borderColor: '#3fb950',
|
|
backgroundColor: 'rgba(63, 185, 80, 0.1)',
|
|
borderWidth: 2,
|
|
tension: 0.3,
|
|
fill: true
|
|
},
|
|
{
|
|
label: 'MiniMax (%)',
|
|
data: minimaxData.length ? minimaxData : [0, 0, 30, 60],
|
|
borderColor: '#d29922',
|
|
backgroundColor: 'rgba(210, 153, 34, 0.1)',
|
|
borderWidth: 2,
|
|
tension: 0.3,
|
|
fill: true
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: {
|
|
labels: { color: '#c9d1d9' }
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
max: 100,
|
|
grid: { color: '#30363d' },
|
|
ticks: { color: '#8b949e' }
|
|
},
|
|
x: {
|
|
grid: { color: '#30363d' },
|
|
ticks: { color: '#8b949e' }
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Apply initial theme to chart
|
|
updateChartTheme(document.body.className);
|
|
} catch (error) {
|
|
console.error('Error fetching history:', error);
|
|
}
|
|
}
|
|
|
|
function updateChartTheme(themeClass) {
|
|
if (!historyChart) return;
|
|
|
|
let colors = ['#58a6ff', '#3fb950', '#d29922']; // Default
|
|
|
|
switch (themeClass) {
|
|
case 'style-pacman':
|
|
colors = ['#f1c40f', '#f39c12', '#e67e22'];
|
|
break;
|
|
case 'style-nyancat':
|
|
colors = ['#ff0000', '#33ff00', '#0099ff'];
|
|
break;
|
|
case 'style-matrix':
|
|
colors = ['#0f0', '#0a0', '#050'];
|
|
break;
|
|
case 'style-lava':
|
|
colors = ['#ff4e00', '#ec9f05', '#bf3a00'];
|
|
break;
|
|
}
|
|
|
|
historyChart.data.datasets.forEach((dataset, index) => {
|
|
dataset.borderColor = colors[index % colors.length];
|
|
|
|
// Convert hex to rgba for background
|
|
let hex = colors[index % colors.length].replace('#', '');
|
|
if (hex.length === 3) {
|
|
hex = hex.split('').map(char => char + char).join('');
|
|
}
|
|
const r = parseInt(hex.substring(0, 2), 16);
|
|
const g = parseInt(hex.substring(2, 4), 16);
|
|
const b = parseInt(hex.substring(4, 6), 16);
|
|
dataset.backgroundColor = `rgba(${r}, ${g}, ${b}, 0.1)`;
|
|
});
|
|
|
|
historyChart.update();
|
|
}
|
|
|