Initial commit — Server_Monitorizare_v2

This commit is contained in:
ske087
2026-04-23 15:55:46 +03:00
commit d2485e4c66
61 changed files with 13861 additions and 0 deletions

241
templates/admin.html Normal file
View File

@@ -0,0 +1,241 @@
{% extends "base.html" %}
{% block title %}Admin — Server Monitoring{% endblock %}
{% block page_title %}Admin & Maintenance{% endblock %}
{% block extra_css %}
<style>
.danger-card { border: 2px solid #dc3545; }
.danger-card .card-header { background-color: #dc3545; color: #fff; }
.warning-card { border: 2px solid #fd7e14; }
.warning-card .card-header { background-color: #fd7e14; color: #fff; }
.stat-box { background: #f8f9fa; border-radius: 8px; padding: 12px 20px; text-align: center; }
.stat-box .num { font-size: 2rem; font-weight: bold; line-height: 1; }
.stat-box .lbl { font-size: .78rem; color: #6c757d; margin-top: 2px; }
</style>
{% endblock %}
{% block content %}
<div class="container-fluid">
<!-- Current stats row -->
<div class="row g-3 mb-4">
<div class="col-12">
<div class="card">
<div class="card-header bg-secondary text-white">
<h5 class="mb-0"><i class="fas fa-database me-2"></i>Current Database &amp; Inventory State</h5>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-6 col-md-2">
<div class="stat-box">
<div class="num text-primary" id="stat-devices">{{ stats.get('devices', '?') }}</div>
<div class="lbl">Devices</div>
</div>
</div>
<div class="col-6 col-md-2">
<div class="stat-box">
<div class="num text-info" id="stat-logs">{{ stats.get('logs', '?') }}</div>
<div class="lbl">Log Entries</div>
</div>
</div>
<div class="col-6 col-md-2">
<div class="stat-box">
<div class="num text-secondary" id="stat-templates">{{ stats.get('templates', '?') }}</div>
<div class="lbl">Msg Templates</div>
</div>
</div>
<div class="col-6 col-md-2">
<div class="stat-box">
<div class="num text-danger" id="stat-wmt">{{ stats.get('wmt_requests', '?') }}</div>
<div class="lbl">WMT Requests</div>
</div>
</div>
<div class="col-6 col-md-2">
<div class="stat-box">
<div class="num text-warning" id="stat-inv-hosts">{{ stats.get('inventory_hosts', '?') }}</div>
<div class="lbl">Inventory Hosts</div>
</div>
</div>
<div class="col-6 col-md-2">
<div class="stat-box">
<div class="num text-success" id="stat-inv-groups">{{ stats.get('inventory_groups_yaml', '?') }}</div>
<div class="lbl">Inventory Groups</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row g-4">
<!-- Clear Log Entries -->
<div class="col-md-3">
<div class="card warning-card h-100">
<div class="card-header">
<h5 class="mb-0"><i class="fas fa-stream me-2"></i>Clear Log Entries</h5>
</div>
<div class="card-body d-flex flex-column">
<p class="text-muted flex-grow-1">
Deletes <strong>all log entries</strong> from the database.
Devices remain intact — they will start logging again automatically.
</p>
<div class="alert alert-warning py-2 mb-3">
<i class="fas fa-exclamation-triangle me-1"></i>
Currently <strong id="badge-logs">{{ stats.get('logs', '?') }}</strong> log entries.
</div>
<button class="btn btn-warning w-100"
onclick="runAction('clear-logs', 'Delete ALL log entries? This cannot be undone.')">
<i class="fas fa-trash me-2"></i>Clear All Logs
</button>
</div>
</div>
</div>
<!-- Clear Devices -->
<div class="col-md-3">
<div class="card danger-card h-100">
<div class="card-header">
<h5 class="mb-0"><i class="fas fa-server me-2"></i>Clear Device Database</h5>
</div>
<div class="card-body d-flex flex-column">
<p class="text-muted flex-grow-1">
Deletes <strong>all devices</strong> and their associated log entries from the database.
Devices will re-register automatically when they next check in.
</p>
<div class="alert alert-danger py-2 mb-3">
<i class="fas fa-exclamation-triangle me-1"></i>
Currently <strong id="badge-devices">{{ stats.get('devices', '?') }}</strong> devices
and <strong id="badge-logs2">{{ stats.get('logs', '?') }}</strong> log entries.
</div>
<button class="btn btn-danger w-100"
onclick="runAction('clear-devices', 'Delete ALL devices and their logs? This cannot be undone.')">
<i class="fas fa-trash me-2"></i>Clear All Devices
</button>
</div>
</div>
</div>
<!-- Clear Ansible Inventory -->
<div class="col-md-3">
<div class="card danger-card h-100">
<div class="card-header">
<h5 class="mb-0"><i class="fas fa-sitemap me-2"></i>Clear Ansible Inventory</h5>
</div>
<div class="card-body d-flex flex-column">
<p class="text-muted flex-grow-1">
Resets the Ansible inventory file and clears all inventory groups.
The file is left fully empty — ready for new hosts and groups.
</p>
<div class="alert alert-danger py-2 mb-3">
<i class="fas fa-exclamation-triangle me-1"></i>
Currently <strong id="badge-inv-hosts">{{ stats.get('inventory_hosts', '?') }}</strong> hosts
in <strong id="badge-inv-groups">{{ stats.get('inventory_groups_yaml', '?') }}</strong> group(s).
</div>
<button class="btn btn-danger w-100"
onclick="runAction('clear-inventory', 'Reset Ansible inventory and delete all groups? This cannot be undone.')">
<i class="fas fa-trash me-2"></i>Clear Inventory
</button>
</div>
</div>
</div>
<!-- Clear WMT Update Requests -->
<div class="col-md-3">
<div class="card warning-card h-100">
<div class="card-header">
<h5 class="mb-0"><i class="fas fa-clipboard-list me-2"></i>Clear WMT Requests</h5>
</div>
<div class="card-body d-flex flex-column">
<p class="text-muted flex-grow-1">
Deletes <strong>all WMT update requests</strong> (pending, accepted and rejected).
Devices are not affected and can submit new requests at any time.
</p>
<div class="alert alert-warning py-2 mb-3">
<i class="fas fa-exclamation-triangle me-1"></i>
Currently <strong id="badge-wmt">{{ stats.get('wmt_requests', '?') }}</strong> update request(s).
</div>
<button class="btn btn-warning w-100"
onclick="runAction('clear-wmt', 'Delete ALL WMT update requests? This cannot be undone.')">
<i class="fas fa-trash me-2"></i>Clear WMT Requests
</button>
</div>
</div>
</div>
</div><!-- /row -->
</div><!-- /container -->
<!-- Result toast -->
<div class="position-fixed bottom-0 end-0 p-3" style="z-index:9999">
<div id="resultToast" class="toast align-items-center text-white border-0" role="alert" aria-live="assertive">
<div class="d-flex">
<div class="toast-body" id="toastMsg">Done.</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
</div>
</div>
</div>
<script>
const ENDPOINTS = {
'clear-logs': '{{ url_for("main.admin_clear_logs") }}',
'clear-devices': '{{ url_for("main.admin_clear_devices") }}',
'clear-inventory': '{{ url_for("main.admin_clear_inventory") }}',
'clear-wmt': '{{ url_for("main.admin_clear_wmt") }}'
};
function runAction(action, confirmMsg) {
if (!confirm(confirmMsg)) return;
const btn = event.currentTarget;
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Working…';
fetch(ENDPOINTS[action], {
method: 'POST',
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then(r => r.json())
.then(data => {
if (data.success) {
showToast('success', buildMessage(action, data));
refreshStats();
} else {
showToast('danger', 'Error: ' + (data.error || 'Unknown'));
}
})
.catch(err => showToast('danger', 'Network error: ' + err))
.finally(() => {
btn.disabled = false;
btn.innerHTML = btn.innerHTML.replace(/<span.*?><\/span>/, '<i class="fas fa-trash me-2"></i>');
// Re-render button label properly
btn.innerHTML = '<i class="fas fa-trash me-2"></i>' + btn.textContent.trim();
});
}
function buildMessage(action, data) {
if (action === 'clear-logs')
return `Deleted ${data.deleted} log entries.`;
if (action === 'clear-devices')
return `Deleted ${data.deleted_devices} devices and ${data.deleted_logs} log entries.`;
if (action === 'clear-inventory')
return `Inventory reset. ${data.groups_deleted} group(s) removed.`;
if (action === 'clear-wmt')
return `Deleted ${data.deleted} WMT update request(s).`;
return 'Done.';
}
function showToast(type, msg) {
const toast = document.getElementById('resultToast');
toast.className = `toast align-items-center text-white bg-${type} border-0`;
document.getElementById('toastMsg').textContent = msg;
bootstrap.Toast.getOrCreateInstance(toast, {delay: 4000}).show();
}
function refreshStats() {
// Reload the page stats after a short delay to let DB settle
setTimeout(() => location.reload(), 800);
}
</script>
{% endblock %}