1488 lines
71 KiB
PHP
1488 lines
71 KiB
PHP
<?php include('include/headscript.php'); ?>
|
|
<!doctype html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
|
|
<?php include('cssinclude.php'); ?>
|
|
|
|
<title>CyberPanel Dashboard - <?= htmlspecialchars($titlewebsite ?? 'Dashboard', ENT_QUOTES, 'UTF-8'); ?></title>
|
|
|
|
<style>
|
|
.dashboard-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 15px;
|
|
flex-wrap: wrap;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.dashboard-title h4 {
|
|
margin-bottom: 4px;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.dashboard-title p {
|
|
margin-bottom: 0;
|
|
color: #6c757d;
|
|
}
|
|
|
|
.action-buttons {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
}
|
|
|
|
.btn-dashboard {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 7px;
|
|
border-radius: 10px;
|
|
padding: 9px 16px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.summary-card {
|
|
border: none;
|
|
border-radius: 14px;
|
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.summary-icon {
|
|
width: 46px;
|
|
height: 46px;
|
|
border-radius: 12px;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 24px;
|
|
}
|
|
|
|
.summary-label {
|
|
color: #6c757d;
|
|
font-size: 13px;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.summary-value {
|
|
font-size: 24px;
|
|
font-weight: 700;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.custom-tabs {
|
|
border-bottom: 1px solid #e5e5e5;
|
|
margin-bottom: 20px;
|
|
gap: 6px;
|
|
}
|
|
|
|
.custom-tabs .nav-link {
|
|
border: none;
|
|
border-radius: 10px 10px 0 0;
|
|
color: #555;
|
|
font-weight: 500;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 10px 18px;
|
|
}
|
|
|
|
.custom-tabs .nav-link:hover {
|
|
background: #f8f9fa;
|
|
color: #0d6efd;
|
|
}
|
|
|
|
.custom-tabs .nav-link.active {
|
|
background: #0d6efd;
|
|
color: #fff;
|
|
}
|
|
|
|
.server-card {
|
|
border: 1px solid #edf0f4;
|
|
border-radius: 16px;
|
|
padding: 18px;
|
|
background: #fff;
|
|
height: 100%;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.server-card:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
|
|
}
|
|
|
|
.server-main {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
margin-bottom: 14px;
|
|
}
|
|
|
|
.server-name {
|
|
font-weight: 700;
|
|
font-size: 17px;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.server-url {
|
|
color: #6c757d;
|
|
font-size: 13px;
|
|
word-break: break-all;
|
|
}
|
|
|
|
.status-badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
border-radius: 50px;
|
|
padding: 5px 10px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.status-online {
|
|
background: #e8f7ef;
|
|
color: #198754;
|
|
}
|
|
|
|
.status-warning {
|
|
background: #fff4dd;
|
|
color: #b7791f;
|
|
}
|
|
|
|
.status-offline {
|
|
background: #fde8e8;
|
|
color: #dc3545;
|
|
}
|
|
|
|
.metric-row {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr 1fr;
|
|
gap: 10px;
|
|
margin: 15px 0;
|
|
}
|
|
|
|
.metric-box {
|
|
border-radius: 12px;
|
|
background: #f8f9fb;
|
|
padding: 10px;
|
|
text-align: center;
|
|
}
|
|
|
|
.metric-label {
|
|
font-size: 12px;
|
|
color: #6c757d;
|
|
margin-bottom: 3px;
|
|
}
|
|
|
|
.metric-value {
|
|
font-weight: 700;
|
|
font-size: 15px;
|
|
}
|
|
|
|
.server-actions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
margin-top: 14px;
|
|
}
|
|
|
|
.server-actions .btn {
|
|
border-radius: 9px;
|
|
font-size: 13px;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
|
|
.domain-table th {
|
|
font-size: 13px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.domain-table td {
|
|
vertical-align: middle;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.progress {
|
|
height: 7px;
|
|
border-radius: 20px;
|
|
}
|
|
|
|
.api-action-card {
|
|
border: 1px solid #edf0f4;
|
|
border-radius: 14px;
|
|
padding: 16px;
|
|
background: #fff;
|
|
height: 100%;
|
|
}
|
|
|
|
.api-action-card h6 {
|
|
font-weight: 700;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.api-action-card p {
|
|
color: #6c757d;
|
|
font-size: 13px;
|
|
min-height: 38px;
|
|
}
|
|
|
|
.log-box {
|
|
background: #101828;
|
|
color: #d0d5dd;
|
|
border-radius: 12px;
|
|
padding: 16px;
|
|
font-family: Consolas, monospace;
|
|
font-size: 13px;
|
|
min-height: 260px;
|
|
overflow: auto;
|
|
}
|
|
|
|
.search-box {
|
|
width: 100%;
|
|
padding: 10px 14px;
|
|
font-size: 15px;
|
|
margin-bottom: 18px;
|
|
border: 1px solid #d9d9d9;
|
|
border-radius: 10px;
|
|
outline: none;
|
|
}
|
|
|
|
.search-box:focus {
|
|
border-color: #0d6efd;
|
|
box-shadow: 0 0 0 0.15rem rgba(13, 110, 253, 0.15);
|
|
}
|
|
|
|
.modal-content {
|
|
border-radius: 16px;
|
|
border: none;
|
|
}
|
|
|
|
.modal-header {
|
|
border-bottom: 1px solid #edf0f4;
|
|
}
|
|
|
|
.modal-footer {
|
|
border-top: 1px solid #edf0f4;
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
.metric-row {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.dashboard-header {
|
|
align-items: flex-start;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<div class="wrapper">
|
|
<?php include('include/navbar.php'); ?>
|
|
<?php include('include/topbar.php'); ?>
|
|
|
|
<div class="page-wrapper">
|
|
<div class="page-content">
|
|
|
|
<?php
|
|
/*
|
|
* Temporary theoretical data.
|
|
* Later this array will be replaced by a SELECT from cyberpanel_servers
|
|
* and real API calls to each CyberPanel instance.
|
|
*/
|
|
|
|
$servers = [];
|
|
|
|
$sql = "
|
|
SELECT
|
|
id,
|
|
name,
|
|
provider,
|
|
ip_address,
|
|
panel_url,
|
|
username,
|
|
api_enabled,
|
|
environment,
|
|
notes,
|
|
last_check,
|
|
last_status
|
|
FROM cyberpanel_servers
|
|
ORDER BY name ASC
|
|
";
|
|
|
|
$stmt = $db->query($sql);
|
|
|
|
if ($stmt) {
|
|
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
|
$servers[] = [
|
|
'id' => (int)$row['id'],
|
|
'name' => $row['name'],
|
|
'panel_url' => $row['panel_url'],
|
|
'provider' => $row['provider'] ?? '',
|
|
'ip' => $row['ip_address'] ?? '',
|
|
'ip_address' => $row['ip_address'] ?? '',
|
|
'username' => $row['username'] ?? '',
|
|
'api_enabled' => (int)$row['api_enabled'],
|
|
'api_status' => ((int)$row['api_enabled'] === 1) ? 'enabled' : 'disabled',
|
|
'environment' => $row['environment'] ?? 'production',
|
|
'notes' => $row['notes'] ?? '',
|
|
'status' => $row['last_status'] ?: 'warning',
|
|
'cpu' => 0,
|
|
'ram' => 0,
|
|
'disk' => 0,
|
|
'websites' => 0,
|
|
'databases' => 0,
|
|
'ssl_expiring' => 0,
|
|
'last_check' => $row['last_check'] ?: '-'
|
|
];
|
|
}
|
|
}
|
|
|
|
$packagesByServer = [];
|
|
|
|
$stmtPackages = $db->query("
|
|
SELECT
|
|
id,
|
|
server_id,
|
|
package_name,
|
|
disk_space,
|
|
bandwidth,
|
|
email_accounts,
|
|
ftp_accounts,
|
|
databases_count,
|
|
domains_count,
|
|
last_sync
|
|
FROM cyberpanel_packages
|
|
ORDER BY package_name ASC
|
|
");
|
|
|
|
if ($stmtPackages) {
|
|
while ($package = $stmtPackages->fetch(PDO::FETCH_ASSOC)) {
|
|
$serverId = (int)$package['server_id'];
|
|
|
|
if (!isset($packagesByServer[$serverId])) {
|
|
$packagesByServer[$serverId] = [];
|
|
}
|
|
|
|
$packagesByServer[$serverId][] = $package;
|
|
}
|
|
}
|
|
|
|
$domains = [
|
|
[
|
|
'domain' => 'yogasoul.it',
|
|
'server' => 'OVH VPS 1',
|
|
'php' => '8.2',
|
|
'ssl' => 'Valid',
|
|
'disk' => '4.8 GB',
|
|
'status' => 'Online',
|
|
'panel_url' => 'https://server1.claudiosironi.com:8090'
|
|
],
|
|
[
|
|
'domain' => 'claudiosironi.com',
|
|
'server' => 'OVH VPS 1',
|
|
'php' => '8.1',
|
|
'ssl' => 'Valid',
|
|
'disk' => '2.1 GB',
|
|
'status' => 'Online',
|
|
'panel_url' => 'https://server1.claudiosironi.com:8090'
|
|
],
|
|
[
|
|
'domain' => 'villadonatella.com',
|
|
'server' => 'Client VPS Keliweb',
|
|
'php' => '8.2',
|
|
'ssl' => 'Expiring',
|
|
'disk' => '8.7 GB',
|
|
'status' => 'Warning',
|
|
'panel_url' => 'https://panel-client.example.com:8090'
|
|
],
|
|
[
|
|
'domain' => 'test-app.local',
|
|
'server' => 'Test Server',
|
|
'php' => '8.3',
|
|
'ssl' => 'Missing',
|
|
'disk' => '1.2 GB',
|
|
'status' => 'Offline',
|
|
'panel_url' => 'https://test-server.example.com:8090'
|
|
]
|
|
];
|
|
|
|
$totalServers = count($servers);
|
|
$onlineServers = count(array_filter($servers, fn($s) => $s['status'] === 'online'));
|
|
$warningServers = count(array_filter($servers, fn($s) => $s['status'] === 'warning'));
|
|
$offlineServers = count(array_filter($servers, fn($s) => $s['status'] === 'offline'));
|
|
$totalWebsites = array_sum(array_column($servers, 'websites'));
|
|
$totalDatabases = array_sum(array_column($servers, 'databases'));
|
|
$totalSslExpiring = array_sum(array_column($servers, 'ssl_expiring'));
|
|
?>
|
|
|
|
<div class="dashboard-header">
|
|
<div class="dashboard-title">
|
|
<h4>CyberPanel Central Dashboard</h4>
|
|
<p>Manage and monitor all your CyberPanel servers from one place.</p>
|
|
</div>
|
|
|
|
<div class="action-buttons">
|
|
<button type="button" class="btn btn-primary btn-dashboard" data-bs-toggle="modal" data-bs-target="#serverModal">
|
|
<i class="bx bx-plus"></i>
|
|
Add New Server
|
|
</button>
|
|
|
|
<button type="button" class="btn btn-outline-primary btn-dashboard" id="btnRefreshAll">
|
|
<i class="bx bx-refresh"></i>
|
|
Refresh All
|
|
</button>
|
|
|
|
<button type="button" class="btn btn-outline-secondary btn-dashboard" data-bs-toggle="modal" data-bs-target="#apiActionModal">
|
|
<i class="bx bx-terminal"></i>
|
|
API Console
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row row-cols-1 row-cols-md-2 row-cols-xl-4 mb-4">
|
|
<div class="col">
|
|
<div class="card summary-card">
|
|
<div class="card-body d-flex align-items-center justify-content-between">
|
|
<div>
|
|
<div class="summary-label">Total Servers</div>
|
|
<p class="summary-value"><?= (int)$totalServers; ?></p>
|
|
</div>
|
|
<div class="summary-icon bg-light-primary text-primary">
|
|
<i class="bx bx-server"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col">
|
|
<div class="card summary-card">
|
|
<div class="card-body d-flex align-items-center justify-content-between">
|
|
<div>
|
|
<div class="summary-label">Online Servers</div>
|
|
<p class="summary-value"><?= (int)$onlineServers; ?></p>
|
|
</div>
|
|
<div class="summary-icon bg-light-success text-success">
|
|
<i class="bx bx-check-circle"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col">
|
|
<div class="card summary-card">
|
|
<div class="card-body d-flex align-items-center justify-content-between">
|
|
<div>
|
|
<div class="summary-label">Websites</div>
|
|
<p class="summary-value"><?= (int)$totalWebsites; ?></p>
|
|
</div>
|
|
<div class="summary-icon bg-light-info text-info">
|
|
<i class="bx bx-globe"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col">
|
|
<div class="card summary-card">
|
|
<div class="card-body d-flex align-items-center justify-content-between">
|
|
<div>
|
|
<div class="summary-label">SSL Expiring</div>
|
|
<p class="summary-value"><?= (int)$totalSslExpiring; ?></p>
|
|
</div>
|
|
<div class="summary-icon bg-light-warning text-warning">
|
|
<i class="bx bx-shield-quarter"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card radius-10">
|
|
<div class="card-body">
|
|
<ul class="nav nav-tabs custom-tabs" id="dashboardTabs" role="tablist">
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link active" id="servers-tab" data-bs-toggle="tab" data-bs-target="#servers-pane" type="button" role="tab">
|
|
<i class="bx bx-server"></i>
|
|
Servers
|
|
</button>
|
|
</li>
|
|
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="domains-tab" data-bs-toggle="tab" data-bs-target="#domains-pane" type="button" role="tab">
|
|
<i class="bx bx-globe"></i>
|
|
Domains / Websites
|
|
</button>
|
|
</li>
|
|
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="actions-tab" data-bs-toggle="tab" data-bs-target="#actions-pane" type="button" role="tab">
|
|
<i class="bx bx-cog"></i>
|
|
CyberPanel Controls
|
|
</button>
|
|
</li>
|
|
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="logs-tab" data-bs-toggle="tab" data-bs-target="#logs-pane" type="button" role="tab">
|
|
<i class="bx bx-list-ul"></i>
|
|
Logs
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
|
|
<div class="tab-content" id="dashboardTabsContent">
|
|
|
|
<div class="tab-pane fade show active" id="servers-pane" role="tabpanel">
|
|
<input type="text" id="serverSearch" class="search-box" placeholder="Search server by name, provider, IP or URL...">
|
|
|
|
<div class="row" id="serverCards">
|
|
<?php foreach ($servers as $server): ?>
|
|
<?php
|
|
$statusClass = 'status-offline';
|
|
$statusIcon = 'bx-x-circle';
|
|
|
|
if ($server['status'] === 'online') {
|
|
$statusClass = 'status-online';
|
|
$statusIcon = 'bx-check-circle';
|
|
} elseif ($server['status'] === 'warning') {
|
|
$statusClass = 'status-warning';
|
|
$statusIcon = 'bx-error-circle';
|
|
}
|
|
?>
|
|
|
|
<div class="col-12 col-md-6 col-xl-4 mb-3 server-item"
|
|
data-search="<?= htmlspecialchars(strtolower($server['name'] . ' ' . $server['provider'] . ' ' . $server['ip'] . ' ' . $server['panel_url']), ENT_QUOTES, 'UTF-8'); ?>">
|
|
|
|
<div class="server-card">
|
|
<div class="server-main">
|
|
<div>
|
|
<div class="server-name"><?= htmlspecialchars($server['name'], ENT_QUOTES, 'UTF-8'); ?></div>
|
|
<div class="server-url"><?= htmlspecialchars($server['panel_url'], ENT_QUOTES, 'UTF-8'); ?></div>
|
|
</div>
|
|
|
|
<div>
|
|
<span class="status-badge <?= $statusClass; ?>">
|
|
<i class="bx <?= $statusIcon; ?>"></i>
|
|
<?= htmlspecialchars(ucfirst($server['status']), ENT_QUOTES, 'UTF-8'); ?>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-2">
|
|
<div class="col-4">
|
|
<small class="text-muted">Provider</small>
|
|
<div class="fw-bold"><?= htmlspecialchars($server['provider'] ?: '-', ENT_QUOTES, 'UTF-8'); ?></div>
|
|
</div>
|
|
|
|
<div class="col-4">
|
|
<small class="text-muted">IP</small>
|
|
<div class="fw-bold"><?= htmlspecialchars($server['ip_address'] ?: '-', ENT_QUOTES, 'UTF-8'); ?></div>
|
|
</div>
|
|
|
|
<div class="col-4">
|
|
<small class="text-muted">Env</small>
|
|
<div class="fw-bold"><?= htmlspecialchars(ucfirst($server['environment'] ?? 'production'), ENT_QUOTES, 'UTF-8'); ?></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="metric-row">
|
|
<div class="metric-box">
|
|
<div class="metric-label">CPU</div>
|
|
<div class="metric-value"><?= (int)$server['cpu']; ?>%</div>
|
|
<div class="progress mt-2">
|
|
<div class="progress-bar" style="width: <?= (int)$server['cpu']; ?>%"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="metric-box">
|
|
<div class="metric-label">RAM</div>
|
|
<div class="metric-value"><?= (int)$server['ram']; ?>%</div>
|
|
<div class="progress mt-2">
|
|
<div class="progress-bar bg-success" style="width: <?= (int)$server['ram']; ?>%"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="metric-box">
|
|
<div class="metric-label">Disk</div>
|
|
<div class="metric-value"><?= (int)$server['disk']; ?>%</div>
|
|
<div class="progress mt-2">
|
|
<div class="progress-bar bg-warning" style="width: <?= (int)$server['disk']; ?>%"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-2">
|
|
<div class="col-4">
|
|
<small class="text-muted">Websites</small>
|
|
<div class="fw-bold"><?= (int)$server['websites']; ?></div>
|
|
</div>
|
|
|
|
<div class="col-4">
|
|
<small class="text-muted">Databases</small>
|
|
<div class="fw-bold"><?= (int)$server['databases']; ?></div>
|
|
</div>
|
|
|
|
<div class="col-4">
|
|
<small class="text-muted">API</small>
|
|
<div class="fw-bold"><?= htmlspecialchars(ucfirst($server['api_status']), ENT_QUOTES, 'UTF-8'); ?></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-3">
|
|
<small class="text-muted">
|
|
Last check:
|
|
<?= htmlspecialchars($server['last_check'], ENT_QUOTES, 'UTF-8'); ?>
|
|
</small>
|
|
</div>
|
|
|
|
<div class="server-actions">
|
|
<a href="<?= htmlspecialchars($server['panel_url'], ENT_QUOTES, 'UTF-8'); ?>" target="_blank" class="btn btn-primary btn-sm">
|
|
<i class="bx bx-link-external"></i>
|
|
Open CyberPanel
|
|
</a>
|
|
|
|
<button type="button" class="btn btn-outline-primary btn-sm btn-edit-server"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#serverModal"
|
|
data-id="<?= (int)$server['id']; ?>"
|
|
data-name="<?= htmlspecialchars($server['name'], ENT_QUOTES, 'UTF-8'); ?>"
|
|
data-url="<?= htmlspecialchars($server['panel_url'], ENT_QUOTES, 'UTF-8'); ?>"
|
|
data-provider="<?= htmlspecialchars($server['provider'] ?? '', ENT_QUOTES, 'UTF-8'); ?>"
|
|
data-ip="<?= htmlspecialchars($server['ip_address'] ?? $server['ip'] ?? '', ENT_QUOTES, 'UTF-8'); ?>"
|
|
data-username="<?= htmlspecialchars($server['username'] ?? '', ENT_QUOTES, 'UTF-8'); ?>"
|
|
data-api-enabled="<?= (int)($server['api_enabled'] ?? 1); ?>"
|
|
data-environment="<?= htmlspecialchars($server['environment'] ?? 'production', ENT_QUOTES, 'UTF-8'); ?>"
|
|
data-notes="<?= htmlspecialchars($server['notes'] ?? '', ENT_QUOTES, 'UTF-8'); ?>">
|
|
<i class="bx bx-edit"></i>
|
|
Edit
|
|
</button>
|
|
|
|
<button type="button" class="btn btn-outline-success btn-sm btn-check-server"
|
|
data-id="<?= (int)$server['id']; ?>">
|
|
<i class="bx bx-refresh"></i>
|
|
Check API
|
|
</button>
|
|
|
|
|
|
<button type="button" class="btn btn-outline-secondary btn-sm btn-server-actions"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#apiActionModal"
|
|
data-server="<?= htmlspecialchars($server['name'], ENT_QUOTES, 'UTF-8'); ?>">
|
|
<i class="bx bx-terminal"></i>
|
|
Actions
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tab-pane fade" id="domains-pane" role="tabpanel">
|
|
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3">
|
|
<div>
|
|
<h6 class="mb-1">Domains / Websites</h6>
|
|
<p class="text-muted mb-0">Theoretical list of websites detected from all CyberPanel servers.</p>
|
|
</div>
|
|
|
|
<button type="button" class="btn btn-primary btn-dashboard" data-bs-toggle="modal" data-bs-target="#apiActionModal">
|
|
<i class="bx bx-plus"></i>
|
|
Create Website
|
|
</button>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-striped table-hover domain-table align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th>Domain</th>
|
|
<th>Server</th>
|
|
<th>PHP</th>
|
|
<th>SSL</th>
|
|
<th>Disk</th>
|
|
<th>Status</th>
|
|
<th class="text-end">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<?php foreach ($domains as $domain): ?>
|
|
<?php
|
|
$domainStatusClass = 'status-online';
|
|
if ($domain['status'] === 'Warning') {
|
|
$domainStatusClass = 'status-warning';
|
|
} elseif ($domain['status'] === 'Offline') {
|
|
$domainStatusClass = 'status-offline';
|
|
}
|
|
?>
|
|
|
|
<tr>
|
|
<td>
|
|
<strong><?= htmlspecialchars($domain['domain'], ENT_QUOTES, 'UTF-8'); ?></strong>
|
|
</td>
|
|
|
|
<td><?= htmlspecialchars($domain['server'], ENT_QUOTES, 'UTF-8'); ?></td>
|
|
|
|
<td>
|
|
<span class="badge bg-light text-dark">
|
|
PHP <?= htmlspecialchars($domain['php'], ENT_QUOTES, 'UTF-8'); ?>
|
|
</span>
|
|
</td>
|
|
|
|
<td><?= htmlspecialchars($domain['ssl'], ENT_QUOTES, 'UTF-8'); ?></td>
|
|
|
|
<td><?= htmlspecialchars($domain['disk'], ENT_QUOTES, 'UTF-8'); ?></td>
|
|
|
|
<td>
|
|
<span class="status-badge <?= $domainStatusClass; ?>">
|
|
<?= htmlspecialchars($domain['status'], ENT_QUOTES, 'UTF-8'); ?>
|
|
</span>
|
|
</td>
|
|
|
|
<td class="text-end">
|
|
<div class="btn-group">
|
|
<a href="<?= htmlspecialchars($domain['panel_url'], ENT_QUOTES, 'UTF-8'); ?>" target="_blank" class="btn btn-sm btn-primary">
|
|
Open Panel
|
|
</a>
|
|
|
|
<button type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown">
|
|
<span class="visually-hidden">Toggle Dropdown</span>
|
|
</button>
|
|
|
|
<ul class="dropdown-menu dropdown-menu-end">
|
|
<li><a class="dropdown-item" href="javascript:;" data-action="view-domain">View details</a></li>
|
|
<li><a class="dropdown-item" href="javascript:;" data-action="issue-ssl">Issue SSL</a></li>
|
|
<li><a class="dropdown-item" href="javascript:;" data-action="change-php">Change PHP version</a></li>
|
|
<li><a class="dropdown-item" href="javascript:;" data-action="backup-domain">Create backup</a></li>
|
|
<li>
|
|
<hr class="dropdown-divider">
|
|
</li>
|
|
<li><a class="dropdown-item text-danger" href="javascript:;" data-action="delete-domain">Delete website</a></li>
|
|
</ul>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tab-pane fade" id="actions-pane" role="tabpanel">
|
|
<div class="row">
|
|
<div class="col-12 col-md-6 col-xl-3 mb-3">
|
|
<div class="api-action-card">
|
|
<h6><i class="bx bx-check-shield text-success"></i> Verify Connection</h6>
|
|
<p>Test API credentials and check if the CyberPanel instance is reachable.</p>
|
|
<button class="btn btn-outline-success btn-sm w-100" data-bs-toggle="modal" data-bs-target="#apiActionModal">
|
|
Run Check
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 col-md-6 col-xl-3 mb-3">
|
|
<div class="api-action-card">
|
|
<h6><i class="bx bx-globe text-primary"></i> List Websites</h6>
|
|
<p>Retrieve all websites configured on the selected CyberPanel server.</p>
|
|
<button class="btn btn-outline-primary btn-sm w-100" data-bs-toggle="modal" data-bs-target="#apiActionModal">
|
|
Load Websites
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 col-md-6 col-xl-3 mb-3">
|
|
<div class="api-action-card">
|
|
<h6><i class="bx bx-data text-info"></i> List Databases</h6>
|
|
<p>Retrieve databases and database users created in CyberPanel.</p>
|
|
<button class="btn btn-outline-info btn-sm w-100" data-bs-toggle="modal" data-bs-target="#apiActionModal">
|
|
Load Databases
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 col-md-6 col-xl-3 mb-3">
|
|
<div class="api-action-card">
|
|
<h6><i class="bx bx-shield-quarter text-warning"></i> SSL Status</h6>
|
|
<p>Check SSL status and detect domains with certificates close to expiration.</p>
|
|
<button class="btn btn-outline-warning btn-sm w-100" data-bs-toggle="modal" data-bs-target="#apiActionModal">
|
|
Check SSL
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 col-md-6 col-xl-3 mb-3">
|
|
<div class="api-action-card">
|
|
<h6><i class="bx bx-plus-circle text-primary"></i> Create Website</h6>
|
|
<p>Create a new website on the selected CyberPanel server.</p>
|
|
<button class="btn btn-outline-primary btn-sm w-100" data-bs-toggle="modal" data-bs-target="#apiActionModal">
|
|
Create Website
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 col-md-6 col-xl-3 mb-3">
|
|
<div class="api-action-card">
|
|
<h6><i class="bx bx-cloud-upload text-secondary"></i> Backup Website</h6>
|
|
<p>Launch a backup operation for a selected website or database.</p>
|
|
<button class="btn btn-outline-secondary btn-sm w-100" data-bs-toggle="modal" data-bs-target="#apiActionModal">
|
|
Start Backup
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 col-md-6 col-xl-3 mb-3">
|
|
<div class="api-action-card">
|
|
<h6><i class="bx bx-envelope text-danger"></i> Email Accounts</h6>
|
|
<p>Read or manage email accounts configured on a specific domain.</p>
|
|
<button class="btn btn-outline-danger btn-sm w-100" data-bs-toggle="modal" data-bs-target="#apiActionModal">
|
|
Manage Email
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 col-md-6 col-xl-3 mb-3">
|
|
<div class="api-action-card">
|
|
<h6><i class="bx bx-terminal text-dark"></i> Raw API Call</h6>
|
|
<p>Send a manual API command for debugging and advanced operations.</p>
|
|
<button class="btn btn-outline-dark btn-sm w-100" data-bs-toggle="modal" data-bs-target="#apiActionModal">
|
|
Open Console
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tab-pane fade" id="logs-pane" role="tabpanel">
|
|
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3">
|
|
<div>
|
|
<h6 class="mb-1">API Logs</h6>
|
|
<p class="text-muted mb-0">Temporary theoretical log area. Later it will read from a database table or log files.</p>
|
|
</div>
|
|
|
|
<button class="btn btn-outline-secondary btn-sm" id="btnClearLogs">
|
|
<i class="bx bx-trash"></i>
|
|
Clear View
|
|
</button>
|
|
</div>
|
|
|
|
<div class="log-box" id="apiLogs">
|
|
[2026-05-20 09:42:11] INFO Checking API connection: OVH VPS 1
|
|
[2026-05-20 09:42:12] OK verifyConn returned success
|
|
[2026-05-20 09:42:14] INFO Loading websites from CyberPanel
|
|
[2026-05-20 09:42:15] OK 8 websites detected
|
|
[2026-05-20 09:42:20] WARN villadonatella.com SSL will expire soon
|
|
[2026-05-20 09:43:02] ERROR Test Server API disabled or unreachable
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal fade" id="serverModal" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg modal-dialog-centered">
|
|
<div class="modal-content">
|
|
<form id="serverForm">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="serverModalTitle">Add New CyberPanel Server</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
|
|
<div class="modal-body">
|
|
<input type="hidden" name="server_id" id="server_id">
|
|
|
|
<div class="row g-3">
|
|
<div class="col-12 col-md-6">
|
|
<label class="form-label">Server Name</label>
|
|
<input type="text" class="form-control" name="server_name" id="server_name" placeholder="Example: OVH VPS 1">
|
|
</div>
|
|
|
|
<div class="col-12 col-md-6">
|
|
<label class="form-label">Provider</label>
|
|
<input type="text" class="form-control" name="provider" id="provider" placeholder="Example: OVH, AWS, Keliweb">
|
|
</div>
|
|
|
|
<div class="col-12 col-md-8">
|
|
<label class="form-label">CyberPanel URL</label>
|
|
<input type="text" class="form-control" name="panel_url" id="panel_url" placeholder="https://server.domain.com:8090">
|
|
</div>
|
|
|
|
<div class="col-12 col-md-4">
|
|
<label class="form-label">IP Address</label>
|
|
<input type="text" class="form-control" name="ip_address" id="ip_address" placeholder="000.000.000.000">
|
|
</div>
|
|
|
|
<div class="col-12 col-md-6">
|
|
<label class="form-label">API Username</label>
|
|
<input type="text" class="form-control" name="api_username" id="api_username" placeholder="admin">
|
|
</div>
|
|
|
|
<div class="col-12 col-md-6">
|
|
<label class="form-label">API Password</label>
|
|
<input type="password" class="form-control" name="api_password" id="api_password" placeholder="CyberPanel password">
|
|
</div>
|
|
|
|
<div class="col-12 col-md-6">
|
|
<label class="form-label">API Status</label>
|
|
<select class="form-select" name="api_enabled" id="api_enabled">
|
|
<option value="1">Enabled</option>
|
|
<option value="0">Disabled</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="col-12 col-md-6">
|
|
<label class="form-label">Environment</label>
|
|
<select class="form-select" name="environment" id="environment">
|
|
<option value="production">Production</option>
|
|
<option value="staging">Staging</option>
|
|
<option value="test">Test</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="col-12">
|
|
<label class="form-label">Notes</label>
|
|
<textarea class="form-control" name="notes" id="notes" rows="3" placeholder="Internal notes..."></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="alert alert-info mt-3 mb-0">
|
|
<strong>Note:</strong> credentials should be encrypted before saving them into MySQL.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
|
|
<button type="button" class="btn btn-outline-primary" id="btnTestConnection">
|
|
<i class="bx bx-plug"></i>
|
|
Test Connection
|
|
</button>
|
|
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="bx bx-save"></i>
|
|
Save Server
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal fade" id="apiActionModal" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg modal-dialog-centered">
|
|
<div class="modal-content">
|
|
<form id="apiActionForm">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">CyberPanel API Action</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
|
|
<div class="card mt-4">
|
|
<div class="card-header bg-white">
|
|
<h6 class="mb-0">
|
|
<i class="bx bx-package"></i>
|
|
Native API Data - Packages
|
|
</h6>
|
|
</div>
|
|
|
|
<div class="card-body">
|
|
<?php if (empty($packagesByServer)): ?>
|
|
<div class="alert alert-info mb-0">
|
|
No native API package data loaded yet. Click <strong>Sync Native API</strong> on a server card.
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="table-responsive">
|
|
<table class="table table-striped table-hover align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th>Server</th>
|
|
<th>Package</th>
|
|
<th>Disk</th>
|
|
<th>Bandwidth</th>
|
|
<th>Email</th>
|
|
<th>FTP</th>
|
|
<th>Databases</th>
|
|
<th>Domains</th>
|
|
<th>Last Sync</th>
|
|
</tr>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<?php foreach ($servers as $server): ?>
|
|
<?php
|
|
$sid = (int)$server['id'];
|
|
$serverPackages = $packagesByServer[$sid] ?? [];
|
|
?>
|
|
|
|
<?php foreach ($serverPackages as $package): ?>
|
|
<tr>
|
|
<td><?= htmlspecialchars($server['name'], ENT_QUOTES, 'UTF-8'); ?></td>
|
|
<td><strong><?= htmlspecialchars($package['package_name'], ENT_QUOTES, 'UTF-8'); ?></strong></td>
|
|
<td><?= htmlspecialchars($package['disk_space'] ?: '-', ENT_QUOTES, 'UTF-8'); ?></td>
|
|
<td><?= htmlspecialchars($package['bandwidth'] ?: '-', ENT_QUOTES, 'UTF-8'); ?></td>
|
|
<td><?= htmlspecialchars($package['email_accounts'] ?: '-', ENT_QUOTES, 'UTF-8'); ?></td>
|
|
<td><?= htmlspecialchars($package['ftp_accounts'] ?: '-', ENT_QUOTES, 'UTF-8'); ?></td>
|
|
<td><?= htmlspecialchars($package['databases_count'] ?: '-', ENT_QUOTES, 'UTF-8'); ?></td>
|
|
<td><?= htmlspecialchars($package['domains_count'] ?: '-', ENT_QUOTES, 'UTF-8'); ?></td>
|
|
<td><?= htmlspecialchars($package['last_sync'] ?: '-', ENT_QUOTES, 'UTF-8'); ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-body">
|
|
<div class="row g-3">
|
|
<div class="col-12 col-md-6">
|
|
<label class="form-label">Server</label>
|
|
<select class="form-select" name="action_server" id="action_server">
|
|
<?php foreach ($servers as $server): ?>
|
|
<option value="<?= (int)$server['id']; ?>">
|
|
<?= htmlspecialchars($server['name'], ENT_QUOTES, 'UTF-8'); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="col-12 col-md-6">
|
|
<label class="form-label">Action</label>
|
|
<select class="form-select" name="api_action" id="api_action">
|
|
<option value="verify_connection">Verify connection</option>
|
|
<option value="list_websites">List websites</option>
|
|
<option value="list_databases">List databases</option>
|
|
<option value="check_ssl">Check SSL status</option>
|
|
<option value="create_website">Create website</option>
|
|
<option value="issue_ssl">Issue SSL</option>
|
|
<option value="create_backup">Create backup</option>
|
|
<option value="raw_call">Raw API call</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="col-12">
|
|
<label class="form-label">Domain / Website</label>
|
|
<input type="text" class="form-control" name="action_domain" id="action_domain" placeholder="example.com">
|
|
</div>
|
|
|
|
<div class="col-12">
|
|
<label class="form-label">Payload / Notes</label>
|
|
<textarea class="form-control" name="action_payload" id="action_payload" rows="6" placeholder='{"domainName": "example.com"}'></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="alert alert-warning mt-3 mb-0">
|
|
This is only the interface. The real API execution will be connected later through PHP endpoints.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Close</button>
|
|
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="bx bx-play"></i>
|
|
Execute Action
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="overlay toggle-icon"></div>
|
|
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
|
<?php include('include/footer.php'); ?>
|
|
</div>
|
|
|
|
<?php include('jsinclude.php'); ?>
|
|
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function() {
|
|
const serverSearch = document.getElementById("serverSearch");
|
|
const serverItems = document.querySelectorAll(".server-item");
|
|
const apiLogs = document.getElementById("apiLogs");
|
|
|
|
if (serverSearch) {
|
|
serverSearch.addEventListener("input", function() {
|
|
const value = this.value.toLowerCase().trim();
|
|
|
|
serverItems.forEach(function(item) {
|
|
const searchText = item.getAttribute("data-search") || "";
|
|
item.style.display = searchText.includes(value) ? "" : "none";
|
|
});
|
|
});
|
|
}
|
|
|
|
document.querySelectorAll(".btn-edit-server").forEach(function(btn) {
|
|
btn.addEventListener("click", function() {
|
|
document.getElementById("serverModalTitle").innerText = "Edit CyberPanel Server";
|
|
|
|
document.getElementById("server_id").value = this.dataset.id || "";
|
|
document.getElementById("server_name").value = this.dataset.name || "";
|
|
document.getElementById("panel_url").value = this.dataset.url || "";
|
|
document.getElementById("provider").value = this.dataset.provider || "";
|
|
document.getElementById("ip_address").value = this.dataset.ip || "";
|
|
document.getElementById("api_username").value = this.dataset.username || "";
|
|
document.getElementById("api_password").value = "";
|
|
document.getElementById("api_enabled").value = this.dataset.apiEnabled || "1";
|
|
document.getElementById("environment").value = this.dataset.environment || "production";
|
|
document.getElementById("notes").value = this.dataset.notes || "";
|
|
});
|
|
});
|
|
|
|
const serverModal = document.getElementById("serverModal");
|
|
|
|
if (serverModal) {
|
|
serverModal.addEventListener("hidden.bs.modal", function() {
|
|
document.getElementById("serverModalTitle").innerText = "Add New CyberPanel Server";
|
|
document.getElementById("serverForm").reset();
|
|
document.getElementById("server_id").value = "";
|
|
});
|
|
}
|
|
|
|
function checkCyberPanelServer(button, showAlert = true) {
|
|
const serverId = button.dataset.id;
|
|
|
|
if (!serverId) {
|
|
alert("Missing server ID.");
|
|
return Promise.resolve(false);
|
|
}
|
|
|
|
button.disabled = true;
|
|
button.innerHTML = '<i class="bx bx-loader bx-spin"></i> Checking...';
|
|
|
|
appendLog("INFO", "Checking CyberPanel API connection for server ID " + serverId);
|
|
|
|
const formData = new FormData();
|
|
formData.append("server_id", serverId);
|
|
|
|
return fetch("ajax/check_cyberpanel_connection.php", {
|
|
method: "POST",
|
|
body: formData
|
|
})
|
|
.then(response => response.text())
|
|
.then(text => {
|
|
let data;
|
|
|
|
try {
|
|
data = JSON.parse(text);
|
|
} catch (e) {
|
|
console.error("RAW RESPONSE:", text);
|
|
appendLog("ERROR", "Invalid JSON response from API check endpoint.");
|
|
|
|
if (showAlert) {
|
|
alert("ERRORE PHP AJAX:\n\n" + text);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
if (data.success) {
|
|
appendLog("OK", data.message);
|
|
|
|
if (showAlert) {
|
|
alert(data.message);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
console.error(data);
|
|
appendLog("ERROR", data.message);
|
|
|
|
if (showAlert) {
|
|
alert(data.message);
|
|
}
|
|
|
|
return false;
|
|
})
|
|
.catch(error => {
|
|
console.error(error);
|
|
appendLog("ERROR", "Unexpected error while checking CyberPanel API.");
|
|
|
|
if (showAlert) {
|
|
alert("Unexpected error while checking CyberPanel API: " + error.message);
|
|
}
|
|
|
|
return false;
|
|
})
|
|
.finally(() => {
|
|
button.disabled = false;
|
|
button.innerHTML = '<i class="bx bx-refresh"></i> Check API';
|
|
});
|
|
}
|
|
|
|
function refreshOneServer(button, showAlert) {
|
|
const serverId = button.dataset.id;
|
|
|
|
if (!serverId) {
|
|
appendLog("ERROR", "Missing server ID.");
|
|
return Promise.resolve(false);
|
|
}
|
|
|
|
const oldHtml = button.innerHTML;
|
|
|
|
button.disabled = true;
|
|
button.innerHTML = '<i class="bx bx-loader bx-spin"></i> Checking...';
|
|
|
|
appendLog("INFO", "Checking server ID " + serverId);
|
|
|
|
const formData = new FormData();
|
|
formData.append("server_id", serverId);
|
|
|
|
return fetch("ajax/check_cyberpanel_connection.php", {
|
|
method: "POST",
|
|
body: formData
|
|
})
|
|
.then(function(response) {
|
|
return response.text();
|
|
})
|
|
.then(function(text) {
|
|
let data;
|
|
|
|
try {
|
|
data = JSON.parse(text);
|
|
} catch (e) {
|
|
console.error("RAW RESPONSE:", text);
|
|
appendLog("ERROR", "Invalid JSON response from server ID " + serverId);
|
|
|
|
if (showAlert) {
|
|
alert("ERRORE PHP AJAX:\n\n" + text);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
if (data.success) {
|
|
appendLog("OK", "Server ID " + serverId + " online");
|
|
return true;
|
|
}
|
|
|
|
appendLog("ERROR", "Server ID " + serverId + " offline: " + data.message);
|
|
|
|
if (showAlert) {
|
|
alert(data.message);
|
|
}
|
|
|
|
return false;
|
|
})
|
|
.catch(function(error) {
|
|
console.error(error);
|
|
appendLog("ERROR", "Unexpected error on server ID " + serverId);
|
|
|
|
if (showAlert) {
|
|
alert("Unexpected error: " + error.message);
|
|
}
|
|
|
|
return false;
|
|
})
|
|
.finally(function() {
|
|
button.disabled = false;
|
|
button.innerHTML = oldHtml;
|
|
});
|
|
}
|
|
|
|
document.querySelectorAll(".btn-check-server").forEach(function(button) {
|
|
button.addEventListener("click", function() {
|
|
refreshOneServer(this, true).then(function() {
|
|
window.location.reload();
|
|
});
|
|
});
|
|
});
|
|
|
|
document.getElementById("btnRefreshAll").addEventListener("click", async function() {
|
|
const refreshAllButton = this;
|
|
const oldHtml = refreshAllButton.innerHTML;
|
|
const buttons = document.querySelectorAll(".btn-check-server");
|
|
|
|
refreshAllButton.disabled = true;
|
|
refreshAllButton.innerHTML = '<i class="bx bx-loader bx-spin"></i> Refreshing...';
|
|
|
|
appendLog("INFO", "Refreshing all servers...");
|
|
|
|
for (const button of buttons) {
|
|
await refreshOneServer(button, false);
|
|
}
|
|
|
|
appendLog("OK", "Refresh all completed.");
|
|
|
|
refreshAllButton.disabled = false;
|
|
refreshAllButton.innerHTML = oldHtml;
|
|
|
|
window.location.reload();
|
|
});
|
|
|
|
document.querySelectorAll(".btn-load-summary").forEach(function(btn) {
|
|
btn.addEventListener("click", function() {
|
|
const serverId = this.dataset.id;
|
|
const button = this;
|
|
|
|
if (!serverId) {
|
|
alert("Missing server ID.");
|
|
return;
|
|
}
|
|
|
|
button.disabled = true;
|
|
button.innerHTML = '<i class="bx bx-loader bx-spin"></i> Loading...';
|
|
|
|
appendLog("INFO", "Loading CyberPanel summary for server ID " + serverId);
|
|
|
|
const formData = new FormData();
|
|
formData.append("server_id", serverId);
|
|
|
|
fetch("ajax/fetch_cyberpanel_summary.php", {
|
|
method: "POST",
|
|
body: formData
|
|
})
|
|
.then(response => response.text())
|
|
.then(text => {
|
|
let data;
|
|
|
|
try {
|
|
data = JSON.parse(text);
|
|
} catch (e) {
|
|
console.error("RAW RESPONSE:", text);
|
|
appendLog("ERROR", "Invalid JSON response from summary endpoint.");
|
|
alert("ERRORE PHP AJAX:\n\n" + text);
|
|
return;
|
|
}
|
|
|
|
if (data.success) {
|
|
appendLog("OK", data.message);
|
|
appendLog("INFO", "Version: " + data.version + " | Packages: " + data.packages_count);
|
|
|
|
alert(
|
|
"Dati caricati:\n\n" +
|
|
"Version: " + data.version + "\n" +
|
|
"Packages: " + data.packages_count
|
|
);
|
|
|
|
setTimeout(function() {
|
|
window.location.reload();
|
|
}, 700);
|
|
} else {
|
|
console.error(data);
|
|
appendLog("ERROR", data.message);
|
|
alert(data.message);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error(error);
|
|
appendLog("ERROR", "Unexpected error while loading CyberPanel summary.");
|
|
alert("Unexpected error while loading CyberPanel summary: " + error.message);
|
|
})
|
|
.finally(() => {
|
|
button.disabled = false;
|
|
button.innerHTML = '<i class="bx bx-data"></i> Load Data';
|
|
});
|
|
});
|
|
});
|
|
|
|
|
|
|
|
document.getElementById("btnTestConnection").addEventListener("click", function() {
|
|
const panelUrl = document.getElementById("panel_url").value;
|
|
|
|
if (!panelUrl) {
|
|
appendLog("WARN", "CyberPanel URL is empty.");
|
|
return;
|
|
}
|
|
|
|
appendLog("INFO", "Testing connection to " + panelUrl);
|
|
appendLog("TODO", "This will call verifyConn through a PHP backend endpoint.");
|
|
});
|
|
|
|
document.getElementById("serverForm").addEventListener("submit", function(event) {
|
|
event.preventDefault();
|
|
|
|
const form = this;
|
|
const formData = new FormData(form);
|
|
|
|
appendLog("INFO", "Saving server configuration...");
|
|
|
|
fetch("ajax/save_cyberpanel_server.php", {
|
|
method: "POST",
|
|
body: formData
|
|
})
|
|
.then(response => {
|
|
return response.text();
|
|
})
|
|
.then(text => {
|
|
let data;
|
|
|
|
try {
|
|
data = JSON.parse(text);
|
|
} catch (e) {
|
|
console.error("RAW SERVER RESPONSE:", text);
|
|
appendLog("ERROR", "Invalid JSON response from save endpoint.");
|
|
alert("ERRORE PHP AJAX:\n\n" + text);
|
|
return;
|
|
}
|
|
|
|
if (data.success) {
|
|
appendLog("OK", data.message);
|
|
|
|
const modalElement = document.getElementById("serverModal");
|
|
const modalInstance = bootstrap.Modal.getInstance(modalElement);
|
|
|
|
if (modalInstance) {
|
|
modalInstance.hide();
|
|
}
|
|
|
|
setTimeout(function() {
|
|
window.location.reload();
|
|
}, 600);
|
|
} else {
|
|
appendLog("ERROR", data.message);
|
|
alert(data.message);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error(error);
|
|
appendLog("ERROR", "Unexpected error while saving server.");
|
|
alert("Unexpected error while saving server: " + error.message);
|
|
});
|
|
});
|
|
|
|
document.getElementById("apiActionForm").addEventListener("submit", function(event) {
|
|
event.preventDefault();
|
|
|
|
const action = document.getElementById("api_action").value;
|
|
const server = document.getElementById("action_server").value;
|
|
|
|
appendLog("INFO", "Executing action: " + action + " on server ID " + server);
|
|
appendLog("TODO", "This will submit to ajax/run_cyberpanel_action.php.");
|
|
});
|
|
|
|
document.getElementById("btnClearLogs").addEventListener("click", function() {
|
|
apiLogs.textContent = "";
|
|
});
|
|
|
|
function appendLog(level, message) {
|
|
if (!apiLogs) return;
|
|
|
|
const now = new Date();
|
|
const timestamp = now.toISOString().replace("T", " ").substring(0, 19);
|
|
apiLogs.textContent += "\n[" + timestamp + "] " + level + " " + message;
|
|
apiLogs.scrollTop = apiLogs.scrollHeight;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html>
|