This commit is contained in:
ilkeral
2025-07-21 13:49:36 +03:00
commit 342f1314c7
57 changed files with 9297 additions and 0 deletions

View File

@ -0,0 +1,445 @@
{% 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 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) {
showToast(data.message, 'success');
setTimeout(() => location.reload(), 2000);
} else {
showToast(data.message, 'error');
}
})
.catch(error => {
showToast('Site 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 %}