Upload unified_dashboard.html
Browse files- unified_dashboard.html +105 -15
unified_dashboard.html
CHANGED
|
@@ -3027,7 +3027,25 @@ Crypto market is bullish today</textarea>
|
|
| 3027 |
if (!stats.market || typeof stats.market !== 'object' || stats.market === null || Array.isArray(stats.market)) {
|
| 3028 |
console.error('Invalid stats.market:', stats.market);
|
| 3029 |
console.error('Full stats object:', JSON.stringify(stats, null, 2));
|
| 3030 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3031 |
}
|
| 3032 |
if (!sentiment || typeof sentiment !== 'object' || sentiment === null) {
|
| 3033 |
throw new Error('دادههای احساسات نامعتبر است: sentiment object not found');
|
|
@@ -3494,7 +3512,17 @@ Crypto market is bullish today</textarea>
|
|
| 3494 |
|
| 3495 |
// Validate data
|
| 3496 |
if (!status || typeof status.total_providers === 'undefined') throw new Error('دادههای وضعیت نامعتبر است');
|
| 3497 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3498 |
|
| 3499 |
if (document.getElementById('totalAPIs')) {
|
| 3500 |
document.getElementById('totalAPIs').textContent = status.total_providers || 0;
|
|
@@ -3510,10 +3538,10 @@ Crypto market is bullish today</textarea>
|
|
| 3510 |
}
|
| 3511 |
|
| 3512 |
if (tbody) {
|
| 3513 |
-
if (
|
| 3514 |
tbody.innerHTML = '<tr><td colspan="5" style="text-align: center; padding: 40px; color: var(--text-secondary);">هیچ APIای یافت نشد</td></tr>';
|
| 3515 |
} else {
|
| 3516 |
-
tbody.innerHTML =
|
| 3517 |
let statusClass = 'badge-success';
|
| 3518 |
if (p.status === 'offline') statusClass = 'badge-danger';
|
| 3519 |
else if (p.status === 'degraded') statusClass = 'badge-warning';
|
|
@@ -3589,18 +3617,68 @@ Crypto market is bullish today</textarea>
|
|
| 3589 |
async function loadAdvancedData() {
|
| 3590 |
try {
|
| 3591 |
const response = await fetch('/api/v2/status');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3592 |
const data = await response.json();
|
| 3593 |
|
| 3594 |
-
|
| 3595 |
-
document.getElementById('
|
| 3596 |
-
|
| 3597 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3598 |
|
| 3599 |
-
|
| 3600 |
-
|
| 3601 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3602 |
} catch (error) {
|
| 3603 |
console.error('Error loading advanced data:', error);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3604 |
}
|
| 3605 |
}
|
| 3606 |
|
|
@@ -3722,12 +3800,24 @@ Crypto market is bullish today</textarea>
|
|
| 3722 |
fetch('/api/providers').then(r => r.json())
|
| 3723 |
]);
|
| 3724 |
|
| 3725 |
-
document.getElementById('statTotal').textContent = status.total_providers;
|
| 3726 |
-
document.getElementById('statOnline').textContent = status.online;
|
| 3727 |
-
document.getElementById('statOffline').textContent = status.offline;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3728 |
|
| 3729 |
const list = document.getElementById('apisList');
|
| 3730 |
-
|
|
|
|
|
|
|
|
|
|
| 3731 |
<div style="background: rgba(17, 24, 39, 0.6); padding: 15px; border-radius: 12px; margin-bottom: 10px; display: flex; justify-content: space-between; align-items: center;">
|
| 3732 |
<div>
|
| 3733 |
<div style="font-weight: 600;">${api.name}</div>
|
|
|
|
| 3027 |
if (!stats.market || typeof stats.market !== 'object' || stats.market === null || Array.isArray(stats.market)) {
|
| 3028 |
console.error('Invalid stats.market:', stats.market);
|
| 3029 |
console.error('Full stats object:', JSON.stringify(stats, null, 2));
|
| 3030 |
+
// Handle both old structure (stats.market) and new structure (stats.summary)
|
| 3031 |
+
// Check if it's the new structure (with summary and providers)
|
| 3032 |
+
if (stats.summary && stats.providers) {
|
| 3033 |
+
// New structure - convert to old structure for compatibility
|
| 3034 |
+
stats.market = {
|
| 3035 |
+
total_market_cap: stats.summary.total_market_cap || 0,
|
| 3036 |
+
total_volume: stats.summary.total_volume || 0,
|
| 3037 |
+
btc_dominance: stats.summary.btc_dominance || 0,
|
| 3038 |
+
active_cryptos: stats.summary.active_cryptos || 0
|
| 3039 |
+
};
|
| 3040 |
+
} else {
|
| 3041 |
+
// Create default market object if missing
|
| 3042 |
+
stats.market = {
|
| 3043 |
+
total_market_cap: 0,
|
| 3044 |
+
total_volume: 0,
|
| 3045 |
+
btc_dominance: 0,
|
| 3046 |
+
active_cryptos: 0
|
| 3047 |
+
};
|
| 3048 |
+
}
|
| 3049 |
}
|
| 3050 |
if (!sentiment || typeof sentiment !== 'object' || sentiment === null) {
|
| 3051 |
throw new Error('دادههای احساسات نامعتبر است: sentiment object not found');
|
|
|
|
| 3512 |
|
| 3513 |
// Validate data
|
| 3514 |
if (!status || typeof status.total_providers === 'undefined') throw new Error('دادههای وضعیت نامعتبر است');
|
| 3515 |
+
|
| 3516 |
+
// Handle providers as both array and object
|
| 3517 |
+
let providersArray = [];
|
| 3518 |
+
if (Array.isArray(providers)) {
|
| 3519 |
+
providersArray = providers;
|
| 3520 |
+
} else if (providers && typeof providers === 'object') {
|
| 3521 |
+
// Convert object to array
|
| 3522 |
+
providersArray = Object.values(providers);
|
| 3523 |
+
} else {
|
| 3524 |
+
throw new Error('لیست APIها نامعتبر است');
|
| 3525 |
+
}
|
| 3526 |
|
| 3527 |
if (document.getElementById('totalAPIs')) {
|
| 3528 |
document.getElementById('totalAPIs').textContent = status.total_providers || 0;
|
|
|
|
| 3538 |
}
|
| 3539 |
|
| 3540 |
if (tbody) {
|
| 3541 |
+
if (providersArray.length === 0) {
|
| 3542 |
tbody.innerHTML = '<tr><td colspan="5" style="text-align: center; padding: 40px; color: var(--text-secondary);">هیچ APIای یافت نشد</td></tr>';
|
| 3543 |
} else {
|
| 3544 |
+
tbody.innerHTML = providersArray.map(p => {
|
| 3545 |
let statusClass = 'badge-success';
|
| 3546 |
if (p.status === 'offline') statusClass = 'badge-danger';
|
| 3547 |
else if (p.status === 'degraded') statusClass = 'badge-warning';
|
|
|
|
| 3617 |
async function loadAdvancedData() {
|
| 3618 |
try {
|
| 3619 |
const response = await fetch('/api/v2/status');
|
| 3620 |
+
if (!response.ok) {
|
| 3621 |
+
// Fallback to /api/status if /api/v2/status doesn't exist
|
| 3622 |
+
const fallbackResponse = await fetch('/api/status');
|
| 3623 |
+
const fallbackData = await fallbackResponse.json();
|
| 3624 |
+
|
| 3625 |
+
if (document.getElementById('totalApis')) {
|
| 3626 |
+
document.getElementById('totalApis').textContent = fallbackData.total_providers || 0;
|
| 3627 |
+
}
|
| 3628 |
+
if (document.getElementById('activeTasks')) {
|
| 3629 |
+
document.getElementById('activeTasks').textContent = 'N/A';
|
| 3630 |
+
}
|
| 3631 |
+
if (document.getElementById('cachedData')) {
|
| 3632 |
+
document.getElementById('cachedData').textContent = 'N/A';
|
| 3633 |
+
}
|
| 3634 |
+
if (document.getElementById('wsConnections')) {
|
| 3635 |
+
document.getElementById('wsConnections').textContent = 'N/A';
|
| 3636 |
+
}
|
| 3637 |
+
return;
|
| 3638 |
+
}
|
| 3639 |
+
|
| 3640 |
const data = await response.json();
|
| 3641 |
|
| 3642 |
+
// Safe property access
|
| 3643 |
+
if (document.getElementById('totalApis')) {
|
| 3644 |
+
document.getElementById('totalApis').textContent = data?.services?.config_loader?.apis_loaded || data?.summary?.total_providers || 0;
|
| 3645 |
+
}
|
| 3646 |
+
if (document.getElementById('activeTasks')) {
|
| 3647 |
+
document.getElementById('activeTasks').textContent = data?.services?.scheduler?.total_tasks || 'N/A';
|
| 3648 |
+
}
|
| 3649 |
+
if (document.getElementById('cachedData')) {
|
| 3650 |
+
document.getElementById('cachedData').textContent = data?.services?.persistence?.cached_apis || 'N/A';
|
| 3651 |
+
}
|
| 3652 |
+
if (document.getElementById('wsConnections')) {
|
| 3653 |
+
document.getElementById('wsConnections').textContent = data?.services?.websocket?.total_connections || 'N/A';
|
| 3654 |
+
}
|
| 3655 |
|
| 3656 |
+
try {
|
| 3657 |
+
const apisResponse = await fetch('/api/v2/config/apis');
|
| 3658 |
+
if (apisResponse.ok) {
|
| 3659 |
+
const apisData = await apisResponse.json();
|
| 3660 |
+
if (apisData?.apis) {
|
| 3661 |
+
displayAPIs(apisData.apis);
|
| 3662 |
+
}
|
| 3663 |
+
}
|
| 3664 |
+
} catch (apiError) {
|
| 3665 |
+
console.warn('Could not load API config:', apiError);
|
| 3666 |
+
}
|
| 3667 |
} catch (error) {
|
| 3668 |
console.error('Error loading advanced data:', error);
|
| 3669 |
+
// Set default values
|
| 3670 |
+
if (document.getElementById('totalApis')) {
|
| 3671 |
+
document.getElementById('totalApis').textContent = 'N/A';
|
| 3672 |
+
}
|
| 3673 |
+
if (document.getElementById('activeTasks')) {
|
| 3674 |
+
document.getElementById('activeTasks').textContent = 'N/A';
|
| 3675 |
+
}
|
| 3676 |
+
if (document.getElementById('cachedData')) {
|
| 3677 |
+
document.getElementById('cachedData').textContent = 'N/A';
|
| 3678 |
+
}
|
| 3679 |
+
if (document.getElementById('wsConnections')) {
|
| 3680 |
+
document.getElementById('wsConnections').textContent = 'N/A';
|
| 3681 |
+
}
|
| 3682 |
}
|
| 3683 |
}
|
| 3684 |
|
|
|
|
| 3800 |
fetch('/api/providers').then(r => r.json())
|
| 3801 |
]);
|
| 3802 |
|
| 3803 |
+
document.getElementById('statTotal').textContent = status.total_providers || 0;
|
| 3804 |
+
document.getElementById('statOnline').textContent = status.online || 0;
|
| 3805 |
+
document.getElementById('statOffline').textContent = status.offline || 0;
|
| 3806 |
+
|
| 3807 |
+
// Handle providers as both array and object
|
| 3808 |
+
let providersArray = [];
|
| 3809 |
+
if (Array.isArray(providers)) {
|
| 3810 |
+
providersArray = providers;
|
| 3811 |
+
} else if (providers && typeof providers === 'object') {
|
| 3812 |
+
// Convert object to array
|
| 3813 |
+
providersArray = Object.values(providers);
|
| 3814 |
+
}
|
| 3815 |
|
| 3816 |
const list = document.getElementById('apisList');
|
| 3817 |
+
if (providersArray.length === 0) {
|
| 3818 |
+
list.innerHTML = '<div style="text-align: center; padding: 40px; color: var(--text-secondary);">هیچ APIای یافت نشد</div>';
|
| 3819 |
+
} else {
|
| 3820 |
+
list.innerHTML = providersArray.map(api => `
|
| 3821 |
<div style="background: rgba(17, 24, 39, 0.6); padding: 15px; border-radius: 12px; margin-bottom: 10px; display: flex; justify-content: space-between; align-items: center;">
|
| 3822 |
<div>
|
| 3823 |
<div style="font-weight: 600;">${api.name}</div>
|