Files
hostpanel/templates/ssh_manager/dashboard.html
ilkeral f4ee7a2d0b yeni
2025-08-08 07:24:25 +03:00

459 lines
17 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends 'ssh_manager/base.html' %}
{% block title %}Dashboard - Hosting Yönetim Paneli{% endblock %}
{% block content %}
<!-- Dashboard Header -->
<div class="row mb-4">
<div class="col-12">
<div class="d-flex justify-content-between align-items-center">
<div>
<h2 class="mb-1">
<i class="bi bi-speedometer2 me-2"></i>Dashboard
</h2>
<p class="text-muted mb-0">Hosting yönetim sistemi genel görünümü</p>
</div>
<div class="text-end">
<small class="text-muted">Son güncelleme: {{ "now"|date:"d.m.Y H:i" }}</small>
</div>
</div>
</div>
</div>
<!-- Dashboard Cards -->
<div class="row g-4 mb-4">
<!-- Toplam Projeler -->
<div class="col-xl-3 col-md-6">
<div class="card dashboard-card h-100">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="icon-box bg-primary bg-opacity-10">
<i class="bi bi-folder-fill text-primary"></i>
</div>
<div class="ms-3">
<h3 class="mb-0">{{ projects.count }}</h3>
<p class="text-muted mb-0">Toplam Proje</p>
</div>
</div>
<div class="mt-3">
<a href="{% url 'projeler' %}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-arrow-right"></i> Projeleri Görüntüle
</a>
</div>
</div>
</div>
</div>
<!-- Aktif Siteler -->
<div class="col-xl-3 col-md-6">
<div class="card dashboard-card h-100">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="icon-box bg-success bg-opacity-10">
<i class="bi bi-globe text-success"></i>
</div>
<div class="ms-3">
<h3 class="mb-0">{{ active_sites_count }}</h3>
<p class="text-muted mb-0">Aktif Site</p>
</div>
</div>
<div class="mt-3">
<button class="btn btn-sm btn-outline-success" onclick="checkAllSites()">
<i class="bi bi-arrow-clockwise"></i> Tümünü Kontrol Et
</button>
</div>
</div>
</div>
</div>
<!-- Toplam Müşteriler -->
<div class="col-xl-3 col-md-6">
<div class="card dashboard-card h-100">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="icon-box bg-info bg-opacity-10">
<i class="bi bi-people text-info"></i>
</div>
<div class="ms-3">
<h3 class="mb-0">{{ customers.count }}</h3>
<p class="text-muted mb-0">Toplam Müşteri</p>
</div>
</div>
<div class="mt-3">
<a href="{% url 'musteriler' %}" class="btn btn-sm btn-outline-info">
<i class="bi bi-arrow-right"></i> Müşterileri Görüntüle
</a>
</div>
</div>
</div>
</div>
<!-- Host Durumu -->
<div class="col-xl-3 col-md-6">
<div class="card dashboard-card h-100">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="icon-box bg-warning bg-opacity-10">
<i class="bi bi-server text-warning"></i>
</div>
<div class="ms-3">
<h3 class="mb-0">{{ online_hosts_count }}/{{ ssh_credentials.count }}</h3>
<p class="text-muted mb-0">Çevrimiçi Host</p>
</div>
</div>
<div class="mt-3 d-flex gap-2">
<button class="btn btn-sm btn-outline-success" onclick="refreshAllHosts()" title="Tüm host durumlarını kontrol et">
<i class="bi bi-arrow-clockwise"></i> Kontrol Et
</button>
<a href="{% url 'host_yonetimi' %}" class="btn btn-sm btn-outline-warning">
<i class="bi bi-gear"></i> Yönet
</a>
</div>
</div>
</div>
</div>
</div>
<!-- Charts Row -->
<div class="row g-4 mb-4">
<!-- Son İşlemler -->
<div class="col-lg-8">
<div class="card h-100">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="bi bi-clock-history me-2"></i>Son İşlemler
</h5>
</div>
<div class="card-body">
{% if recent_logs %}
<div class="table-responsive">
<table class="table table-dark table-sm">
<thead>
<tr>
<th>Tarih</th>
<th>İşlem</th>
<th>Proje</th>
<th>Durum</th>
</tr>
</thead>
<tbody>
{% for log in recent_logs|slice:":10" %}
<tr>
<td>
<small>{{ log.created_at|date:"d.m H:i" }}</small>
</td>
<td>
<i class="bi {% if log.log_type == 'backup' %}bi-cloud-arrow-up text-warning{% elif log.log_type == 'command' %}bi-terminal text-info{% else %}bi-gear text-secondary{% endif %}"></i>
{{ log.get_log_type_display }}
</td>
<td>
{% if log.ssh_credential %}
<small>{{ log.ssh_credential.name }}</small>
{% else %}
<small class="text-muted">-</small>
{% endif %}
</td>
<td>
<span class="badge {% if log.status == 'success' %}bg-success{% else %}bg-danger{% endif %} fs-6">
{{ log.get_status_display }}
</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="text-center mt-3">
<a href="{% url 'islem_gecmisi' %}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-list-ul"></i> Tüm İşlem Geçmişi
</a>
</div>
{% else %}
<div class="text-center py-4">
<i class="bi bi-clock-history" style="font-size: 2rem; color: #6c757d;"></i>
<p class="text-muted mt-2">Henüz işlem geçmişi yok</p>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Sistem Durumu -->
<div class="col-lg-4">
<div class="card h-100">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="bi bi-activity me-2"></i>Sistem Durumu
</h5>
</div>
<div class="card-body">
<!-- Host Durumları -->
<div class="mb-4">
<h6 class="text-muted mb-3">Host Durumları</h6>
{% for host in ssh_credentials|slice:":5" %}
<div class="d-flex justify-content-between align-items-center mb-2">
<span class="small">{{ host.name }}</span>
<span class="badge {% if host.connection_status == 'connected' %}bg-success{% elif host.connection_status == 'failed' %}bg-danger{% else %}bg-secondary{% endif %}">
{% if host.connection_status == 'connected' %}Bağlı{% elif host.connection_status == 'failed' %}Hata{% else %}Bilinmiyor{% endif %}
</span>
</div>
{% empty %}
<p class="text-muted small">Host tanımlanmamış</p>
{% endfor %}
</div>
<!-- Disk Kullanımı -->
<div class="mb-4">
<h6 class="text-muted mb-3">Disk Kullanımı</h6>
{% for host in ssh_credentials %}
{% if host.disk_usage %}
<div class="mb-3">
<div class="d-flex justify-content-between align-items-center mb-1">
<small>{{ host.name }}</small>
<small>{{ host.disk_usage }}%</small>
</div>
<div class="progress" style="height: 6px;">
<div class="progress-bar {% if host.disk_usage > 80 %}bg-danger{% elif host.disk_usage > 60 %}bg-warning{% else %}bg-success{% endif %}"
style="width: {{ host.disk_usage }}%"></div>
</div>
</div>
{% endif %}
{% endfor %}
</div>
<!-- Hızlı İşlemler -->
<div>
<h6 class="text-muted mb-3">Hızlı İşlemler</h6>
<div class="d-grid gap-2">
<button class="btn btn-sm btn-outline-primary" onclick="refreshAllData()">
<i class="bi bi-arrow-clockwise"></i> Tüm Verileri Yenile
</button>
<a href="{% url 'yedeklemeler' %}" class="btn btn-sm btn-outline-warning">
<i class="bi bi-cloud-arrow-up"></i> Yedekleme Başlat
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Son Yedeklemeler -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="bi bi-cloud-arrow-up me-2"></i>Son Yedeklemeler
</h5>
</div>
<div class="card-body">
{% if recent_backups %}
<div class="row">
{% for project in recent_backups|slice:":6" %}
<div class="col-lg-4 col-md-6 mb-3">
<div class="backup-item">
<div class="d-flex justify-content-between align-items-center">
<div>
<h6 class="mb-1">{{ project.name }}</h6>
<small class="text-muted">
{% if project.last_backup %}
{{ project.last_backup|date:"d.m.Y H:i" }}
{% else %}
Yedek alınmamış
{% endif %}
</small>
</div>
<div>
{% if project.last_backup %}
<span class="badge bg-success">Tamam</span>
{% else %}
<span class="badge bg-warning">Bekliyor</span>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<div class="text-center mt-3">
<a href="{% url 'yedeklemeler' %}" class="btn btn-outline-primary">
<i class="bi bi-cloud-arrow-up"></i> Tüm Yedeklemeler
</a>
</div>
{% else %}
<div class="text-center py-4">
<i class="bi bi-cloud-arrow-up" style="font-size: 2rem; color: #6c757d;"></i>
<p class="text-muted mt-2">Henüz yedekleme yapılmamış</p>
<button class="btn btn-primary" onclick="startBackup()">
<i class="bi bi-cloud-arrow-up"></i> İlk Yedeklemeyi Başlat
</button>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<style>
.dashboard-card {
border: none;
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.5);
transition: transform 0.2s ease-in-out;
}
.dashboard-card:hover {
transform: translateY(-2px);
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.7);
}
.icon-box {
width: 60px;
height: 60px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
}
.icon-box i {
font-size: 1.5rem;
}
.backup-item {
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.card {
background: #23272b;
border: 1px solid #444;
}
.card-header {
background: #1a1d23;
border-bottom: 1px solid #444;
}
.progress {
background-color: rgba(255, 255, 255, 0.1);
}
</style>
<script>
// Tüm host durumlarını kontrol et
function refreshAllHosts() {
showToast('Host durumları kontrol ediliyor...', 'info');
fetch('/refresh-all-hosts/', {
method: 'POST',
headers: {
'X-CSRFToken': getCookie('csrftoken'),
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showToast('Host durumları başarıyla güncellendi', 'success');
setTimeout(() => location.reload(), 1000);
} else {
showToast('Host kontrol hatası: ' + (data.message || 'Bilinmeyen hata'), 'error');
}
})
.catch(error => {
console.error('Host kontrol hatası:', error);
showToast('Host kontrol hatası', 'error');
});
}
// Tüm siteleri kontrol et
function checkAllSites() {
showToast('Tüm siteler ve disk kullanımları kontrol ediliyor...', 'info');
fetch('/check-all-sites/', {
method: 'POST',
headers: {
'X-CSRFToken': getCookie('csrftoken'),
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Sonuçları göster
const activeCount = data.results.filter(r => r.status).length;
const totalCount = data.results.length;
// Özet mesaj oluştur
const summaryMessage = `
<div>
<div><strong>Site Kontrolü Tamamlandı</strong></div>
<div class="mt-2">${activeCount}/${totalCount} site aktif</div>
<div class="small text-muted mt-1">Disk kullanımları güncellendi</div>
</div>
`;
showToast(summaryMessage, 'success', 5000);
setTimeout(() => location.reload(), 2000);
} else {
showToast(data.message, 'error');
}
})
.catch(error => {
showToast('Site ve disk kontrolü hatası', 'error');
});
}
// Tüm verileri yenile
function refreshAllData() {
showToast('Veriler yenileniyor...', 'info');
fetch('/refresh-all-hosts/', {
method: 'POST',
headers: {
'X-CSRFToken': getCookie('csrftoken'),
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showToast('Veriler başarıyla yenilendi', 'success');
setTimeout(() => location.reload(), 1000);
} else {
showToast('Veri yenileme hatası', 'error');
}
})
.catch(error => {
showToast('Veri yenileme hatası', 'error');
});
}
// Yedekleme başlat
function startBackup() {
showToast('Yedekleme işlemi başlatılıyor...', 'info');
// Yedekleme sayfasına yönlendir
window.location.href = '{% url "yedeklemeler" %}';
}
// Sayfa yüklendiğinde otomatik host kontrol (opsiyonel)
document.addEventListener('DOMContentLoaded', function() {
// Son host kontrolünden 10 dakika geçtiyse otomatik kontrol et
const lastCheck = localStorage.getItem('lastHostCheck');
const now = new Date().getTime();
if (!lastCheck || (now - parseInt(lastCheck)) > 10 * 60 * 1000) { // 10 dakika
// Sessizce host durumlarını kontrol et (sadece ilk açılışta)
setTimeout(() => {
console.log('Otomatik host kontrolü başlatılıyor...');
refreshAllHosts();
localStorage.setItem('lastHostCheck', now.toString());
}, 2000); // 2 saniye sonra başlat
}
});
</script>
{% endblock %}