Files
atlas/web/templates/dashboard.html
Othman Hendy Suseo 6202ef8e83
Some checks failed
CI / test-build (push) Has been cancelled
fixing UI and iscsi sync
2025-12-20 19:16:50 +00:00

207 lines
9.3 KiB
HTML

{{define "content"}}
<div class="space-y-6">
<div>
<h1 class="text-3xl font-bold text-white mb-2">Dashboard</h1>
<p class="text-slate-400">Welcome to AtlasOS Storage Controller</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
<!-- Storage Pools Card -->
<div class="bg-slate-800 rounded-lg p-6 border border-slate-700">
<div class="flex items-center justify-between mb-4">
<h2 class="text-lg font-semibold text-white">Pools</h2>
<div class="h-10 w-10 rounded-lg bg-slate-700 flex items-center justify-center">
<svg class="w-6 h-6 text-slate-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"></path>
</svg>
</div>
</div>
<p class="text-2xl font-bold text-white mb-1" id="pool-count">-</p>
<p class="text-sm text-slate-400">Storage Pools</p>
</div>
<!-- Storage Capacity Card -->
<div class="bg-slate-800 rounded-lg p-6 border border-slate-700">
<div class="flex items-center justify-between mb-4">
<h2 class="text-lg font-semibold text-white">Capacity</h2>
<div class="h-10 w-10 rounded-lg bg-slate-700 flex items-center justify-center">
<svg class="w-6 h-6 text-slate-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
</svg>
</div>
</div>
<p class="text-2xl font-bold text-white mb-1" id="total-capacity">-</p>
<p class="text-sm text-slate-400">Total Capacity</p>
</div>
<!-- Shares Card -->
<div class="bg-slate-800 rounded-lg p-6 border border-slate-700">
<div class="flex items-center justify-between mb-4">
<h2 class="text-lg font-semibold text-white">Shares</h2>
<div class="h-10 w-10 rounded-lg bg-slate-700 flex items-center justify-center">
<svg class="w-6 h-6 text-slate-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
</svg>
</div>
</div>
<p class="text-2xl font-bold text-white mb-1" id="smb-shares">-</p>
<p class="text-sm text-slate-400">SMB + NFS</p>
</div>
<!-- iSCSI Targets Card -->
<div class="bg-slate-800 rounded-lg p-6 border border-slate-700">
<div class="flex items-center justify-between mb-4">
<h2 class="text-lg font-semibold text-white">iSCSI</h2>
<div class="h-10 w-10 rounded-lg bg-slate-700 flex items-center justify-center">
<svg class="w-6 h-6 text-slate-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
</svg>
</div>
</div>
<p class="text-2xl font-bold text-white mb-1" id="iscsi-targets">-</p>
<p class="text-sm text-slate-400">Active Targets</p>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- System Status -->
<div class="bg-slate-800 rounded-lg p-6 border border-slate-700">
<h2 class="text-lg font-semibold text-white mb-4">Service Status</h2>
<div class="space-y-3">
<div class="flex items-center justify-between">
<span class="text-slate-300">SMB/Samba</span>
<span id="smb-status" class="px-3 py-1 rounded-full text-xs font-medium bg-slate-700 text-slate-300">-</span>
</div>
<div class="flex items-center justify-between">
<span class="text-slate-300">NFS Server</span>
<span id="nfs-status" class="px-3 py-1 rounded-full text-xs font-medium bg-slate-700 text-slate-300">-</span>
</div>
<div class="flex items-center justify-between">
<span class="text-slate-300">iSCSI Target</span>
<span id="iscsi-status" class="px-3 py-1 rounded-full text-xs font-medium bg-slate-700 text-slate-300">-</span>
</div>
<div class="flex items-center justify-between">
<span class="text-slate-300">API Status</span>
<span class="px-3 py-1 rounded-full text-xs font-medium bg-green-900 text-green-300">Online</span>
</div>
</div>
</div>
<!-- Jobs Status -->
<div class="bg-slate-800 rounded-lg p-6 border border-slate-700">
<h2 class="text-lg font-semibold text-white mb-4">Jobs</h2>
<div class="space-y-3">
<div class="flex items-center justify-between">
<span class="text-slate-300">Running</span>
<span id="jobs-running" class="text-white font-semibold">-</span>
</div>
<div class="flex items-center justify-between">
<span class="text-slate-300">Completed</span>
<span id="jobs-completed" class="text-white font-semibold">-</span>
</div>
<div class="flex items-center justify-between">
<span class="text-slate-300">Failed</span>
<span id="jobs-failed" class="text-white font-semibold">-</span>
</div>
<div class="flex items-center justify-between">
<span class="text-slate-300">Total</span>
<span id="jobs-total" class="text-white font-semibold">-</span>
</div>
</div>
</div>
</div>
<!-- Recent Activity -->
<div class="bg-slate-800 rounded-lg p-6 border border-slate-700">
<h2 class="text-lg font-semibold text-white mb-4">Recent Activity</h2>
<div id="recent-logs" class="space-y-2">
<p class="text-slate-400 text-sm">Loading...</p>
</div>
</div>
</div>
<script>
// Check authentication on page load
(function() {
const token = localStorage.getItem('atlas_token');
if (!token) {
// No token, redirect to login
window.location.href = '/login?return=' + encodeURIComponent(window.location.pathname);
return;
}
})();
// Fetch dashboard data and update UI
function updateDashboard() {
fetch('/api/v1/dashboard')
.then(res => {
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
return res.json();
})
.then(data => {
// Update storage stats
document.getElementById('pool-count').textContent = data.storage.pool_count || 0;
document.getElementById('total-capacity').textContent = formatBytes(data.storage.total_capacity || 0);
// Display total shares (SMB + NFS)
const totalShares = (data.services.smb_shares || 0) + (data.services.nfs_exports || 0);
document.getElementById('smb-shares').textContent = totalShares;
document.getElementById('iscsi-targets').textContent = data.services.iscsi_targets || 0;
// Update service status
updateStatus('smb-status', data.services.smb_status);
updateStatus('nfs-status', data.services.nfs_status);
updateStatus('iscsi-status', data.services.iscsi_status);
// Update jobs
document.getElementById('jobs-running').textContent = data.jobs.running || 0;
document.getElementById('jobs-completed').textContent = data.jobs.completed || 0;
document.getElementById('jobs-failed').textContent = data.jobs.failed || 0;
document.getElementById('jobs-total').textContent = data.jobs.total || 0;
// Update recent logs
const logsDiv = document.getElementById('recent-logs');
if (data.recent_audit_logs && data.recent_audit_logs.length > 0) {
logsDiv.innerHTML = data.recent_audit_logs.map(log => `
<div class="flex items-center justify-between text-sm">
<span class="text-slate-300">${log.action} ${log.resource}</span>
<span class="px-2 py-1 rounded text-xs ${log.result === 'success' ? 'bg-green-900 text-green-300' : 'bg-red-900 text-red-300'}">${log.result}</span>
</div>
`).join('');
} else {
logsDiv.innerHTML = '<p class="text-slate-400 text-sm">No recent activity</p>';
}
})
.catch(err => console.error('Dashboard update error:', err));
}
function updateStatus(id, status) {
const el = document.getElementById(id);
if (status) {
el.className = 'px-3 py-1 rounded-full text-xs font-medium bg-green-900 text-green-300';
el.textContent = 'Running';
} else {
el.className = 'px-3 py-1 rounded-full text-xs font-medium bg-red-900 text-red-300';
el.textContent = 'Stopped';
}
}
function formatBytes(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
}
// Initial load and periodic updates
updateDashboard();
setInterval(updateDashboard, 30000); // Update every 30 seconds
</script>
{{end}}
{{define "dashboard.html"}}
{{template "base" .}}
{{end}}