Files
server-manager/views/servers/show.php
Agent 88f3c1f964 refactor: extract inline CSS/JS from views into separate asset files (20+ files)
Phase A — HTML removed from PHP files:
- RateLimitMiddleware.php: heredoc moved to views/errors/429.php
- public/index.php: inline HTML replaced with View::error()
- AuthMiddleware.php: <script> redirect replaced with <meta refresh>

Phase B — Inline CSS/JS extracted from views:
- CSS: landing.css (459 lines), legal.css (shared by terms+privacy)
- JS: 17 new files extracted from ~20 view files
  - main.js (layout sidebar + notifications)
  - dashboard-chart.js, server-show.js, server-services.js
  - nginx-manager.js, database-manager.js
  - terminal.js, team-show.js, team-index.js
  - server-list.js, server-permissions.js (shared by edit+create)
  - server-ssl.js, server-processes.js, system-users.js
  - admin-users.js, audit-log.js, admin-notifications.js, admin-security.js
  - notifications.js

Total: -3264 lines from views, +288 lines in new assets
2026-06-14 08:04:01 -04:00

379 lines
18 KiB
PHP

<?php
$server = $server ?? [];
$metrics = $metrics ?? null;
$historicalMetrics = $historicalMetrics ?? [];
$server_role = $server_role ?? null;
$canManage = $server_role === 'owner' || $server_role === 'manager';
?>
<div class="page-header">
<div class="page-header-left">
<div class="back-link">
<a href="/servers"><i class="fas fa-arrow-left"></i> Back to Servers</a>
</div>
<h1 class="page-title"><?= htmlspecialchars($server['name'] ?? 'Unknown') ?></h1>
<p class="page-subtitle">
<?= htmlspecialchars($server['ip_address'] ?? '') ?>:<?= $server['ssh_port'] ?? 22 ?>
&middot;
<span class="status-badge status-<?= $server['current_status'] ?? 'unknown' ?>">
<?= ucfirst($server['current_status'] ?? 'unknown') ?>
</span>
</p>
</div>
<div class="page-header-right">
<div class="btn-group">
<span class="badge badge-<?= $server_role === 'owner' || $server_role === 'manager' ? 'warning' : 'info' ?>" style="align-self:center">
<?= htmlspecialchars(ucfirst($server_role ?? 'viewer')) ?>
</span>
<a href="/terminal/<?= $server['id'] ?>" class="btn btn-dark">
<i class="fas fa-terminal"></i> Terminal
</a>
<?php if ($canManage): ?>
<a href="/servers/<?= $server['id'] ?>/edit" class="btn btn-secondary">
<i class="fas fa-edit"></i> Edit
</a>
<?php endif; ?>
<?php if ($canManage): ?>
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle">
<i class="fas fa-cog"></i> Actions
</button>
<div class="dropdown-menu">
<button onclick="serverAction('reboot')" class="dropdown-item">
<i class="fas fa-redo"></i> Reboot
</button>
<button onclick="serverAction('shutdown')" class="dropdown-item text-danger">
<i class="fas fa-power-off"></i> Shutdown
</button>
<div class="dropdown-divider"></div>
<button onclick="serverAction('test-connection')" class="dropdown-item">
<i class="fas fa-plug"></i> Test Connection
</button>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
<?php if ($server['description'] ?? ''): ?>
<div class="card card-description">
<div class="card-body">
<p><?= nl2br(htmlspecialchars($server['description'])) ?></p>
</div>
</div>
<?php endif; ?>
<div class="stats-grid">
<div class="stat-card stat-card-info">
<div class="stat-icon"><i class="fas fa-microchip"></i></div>
<div class="stat-info">
<span class="stat-value" id="cpuMetric"><?= $metrics['cpu_usage'] ?? '-' ?>%</span>
<span class="stat-label">CPU Usage</span>
</div>
</div>
<div class="stat-card stat-card-warning">
<div class="stat-icon"><i class="fas fa-memory"></i></div>
<div class="stat-info">
<span class="stat-value" id="ramMetric"><?= $metrics['ram_usage'] ?? '-' ?>%</span>
<span class="stat-label">RAM Usage</span>
</div>
</div>
<div class="stat-card stat-card-purple">
<div class="stat-icon"><i class="fas fa-hdd"></i></div>
<div class="stat-info">
<span class="stat-value" id="diskMetric"><?= $metrics['disk_usage'] ?? '-' ?>%</span>
<span class="stat-label">Disk Usage</span>
</div>
</div>
<div class="stat-card stat-card-primary">
<div class="stat-icon"><i class="fas fa-tachometer-alt"></i></div>
<div class="stat-info">
<span class="stat-value" id="loadMetric"><?= $metrics['load_average'] ?? '-' ?></span>
<span class="stat-label">Load Average</span>
</div>
</div>
<div class="stat-card stat-card-success">
<div class="stat-icon"><i class="fas fa-clock"></i></div>
<div class="stat-info">
<span class="stat-value" id="uptimeMetric"><?= htmlspecialchars($metrics['uptime'] ?? '-') ?></span>
<span class="stat-label">Uptime</span>
</div>
</div>
</div>
<div class="dashboard-grid">
<div class="dashboard-card">
<div class="card-header">
<h2><i class="fas fa-chart-line"></i> Resource Usage (24h)</h2>
</div>
<div class="card-body">
<canvas id="metricsChart" height="300"></canvas>
</div>
</div>
<div class="dashboard-card">
<div class="card-header">
<h2><i class="fas fa-info-circle"></i> Connection Details</h2>
</div>
<div class="card-body">
<dl class="details-list">
<dt>Host</dt>
<dd><code><?= htmlspecialchars($server['ip_address'] ?? '') ?></code></dd>
<dt>SSH Port</dt>
<dd><?= $server['ssh_port'] ?? 22 ?></dd>
<dt>SSH User</dt>
<dd><?= htmlspecialchars($server['ssh_user'] ?? '') ?></dd>
<dt>Auth Method</dt>
<dd>
<?php if (!empty($server['ssh_key'])): ?>
<span class="badge badge-info">Key-based</span>
<?php else: ?>
<span class="badge badge-warning">Password</span>
<?php endif; ?>
</dd>
<dt>Group</dt>
<dd><?= htmlspecialchars($server['group_name'] ?? 'None') ?></dd>
<dt>Last Check</dt>
<dd><?= $server['last_check_at'] ?? 'Never' ?></dd>
</dl>
</div>
</div>
<div class="dashboard-card">
<div class="card-header">
<h2><i class="fas fa-wifi"></i> Monitoring Agent</h2>
</div>
<div class="card-body">
<?php if (!empty($server['agent_key'])): ?>
<dl class="details-list">
<dt>Agent Key</dt>
<dd>
<code id="agentKeyDisplay"><?= substr($server['agent_key'], 0, 12) ?>...<?= substr($server['agent_key'], -4) ?></code>
<button class="btn btn-sm btn-secondary" onclick="copyAgentKey()" title="Copy full key">
<i class="fas fa-copy"></i>
</button>
<input type="hidden" id="agentKeyFull" value="<?= htmlspecialchars($server['agent_key']) ?>">
</dd>
<dt>Status</dt>
<dd>
<?php if ($server['agent_installed'] ?? false): ?>
<span class="badge badge-success">Installed</span>
<?php else: ?>
<span class="badge badge-secondary">Not installed</span>
<?php endif; ?>
</dd>
<?php if (!empty($server['agent_install_path'])): ?>
<dt>Install Path</dt>
<dd><code><?= htmlspecialchars($server['agent_install_path']) ?></code></dd>
<?php endif; ?>
<dt>Last Seen</dt>
<dd><?= $server['agent_last_seen_at'] ?? 'Never' ?></dd>
</dl>
<div class="form-actions" style="margin-top:1rem">
<?php if ($canManage): ?>
<?php if ($server['agent_installed'] ?? false): ?>
<button onclick="showAgentModal('uninstall')" class="btn btn-danger">
<i class="fas fa-minus-circle"></i> Uninstall Agent
</button>
<?php else: ?>
<button onclick="showAgentModal('install')" class="btn btn-primary">
<i class="fas fa-plus-circle"></i> Install Agent
</button>
<?php endif; ?>
<button onclick="regenerateAgentKey()" class="btn btn-secondary" title="Regenerate agent key">
<i class="fas fa-key"></i> Regenerate Key
</button>
<?php endif; ?>
</div>
<?php else: ?>
<p class="text-muted">No agent key configured.</p>
<?php endif; ?>
</div>
</div>
<?php if (!empty($permissions)): ?>
<div class="dashboard-card">
<div class="card-header">
<h2><i class="fas fa-shield-alt"></i> Required Permissions</h2>
</div>
<div class="card-body">
<table class="table table-sm">
<thead>
<tr>
<th>Type</th>
<th>Value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<?php foreach ($permissions as $perm): ?>
<tr>
<td><span class="badge badge-info"><?= htmlspecialchars($perm['permission_type'] ?? '') ?></span></td>
<td><code><?= htmlspecialchars($perm['permission_value'] ?? '') ?></code></td>
<td><?= htmlspecialchars($perm['description'] ?? '') ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
</div>
<div class="card">
<div class="card-header">
<h2><i class="fas fa-tools"></i> Management Actions</h2>
</div>
<div class="card-body">
<div class="action-grid">
<a href="/terminal/<?= $server['id'] ?>" class="action-card">
<i class="fas fa-terminal"></i>
<span>Web Terminal</span>
</a>
<a href="/servers/<?= $server['id'] ?>/processes" class="action-card">
<i class="fas fa-tasks"></i>
<span>Processes</span>
</a>
<a href="/servers/<?= $server['id'] ?>/system-info" class="action-card">
<i class="fas fa-info-circle"></i>
<span>System Info</span>
</a>
<a href="/servers/<?= $server['id'] ?>/logs" class="action-card">
<i class="fas fa-file-alt"></i>
<span>System Logs</span>
</a>
<?php if ($canManage): ?>
<a href="/servers/<?= $server['id'] ?>/nginx" class="action-card">
<svg viewBox="0 0 24 24" fill="currentColor" width="24" height="24" style="opacity:0.8">
<path d="M12 2L2 7.2v9.6L12 22l10-5.2V7.2L12 2zm0 1.5l8.5 4.4v8.2L12 20.5l-8.5-4.4V7.9L12 3.5zM7.4 8.5v7l1.5.9V11l3.1 4.3 1.5.9V8.5l-1.5.9v4.4L8.9 9.4l-1.5-.9zm9.2 0l-1.5.9-3.1 4.4V17l1.5-.9V11l3.1-4.3z"/>
</svg>
<span>Nginx</span>
</a>
<a href="/servers/<?= $server['id'] ?>/ssl" class="action-card">
<i class="fas fa-shield-alt"></i>
<span>SSL Certificates</span>
</a>
<a href="/servers/<?= $server['id'] ?>/database" class="action-card">
<i class="fas fa-database"></i>
<span>Database Manager</span>
</a>
<a href="/servers/<?= $server['id'] ?>/users" class="action-card">
<i class="fas fa-users-cog"></i>
<span>System Users</span>
</a>
<a href="/servers/<?= $server['id'] ?>/services" class="action-card">
<i class="fas fa-cogs"></i>
<span>Services</span>
</a>
<button class="action-card" onclick="restartService()">
<i class="fas fa-sync-alt"></i>
<span>Restart Service</span>
</button>
<?php if ($server_role === 'owner'): ?>
<button class="action-card" onclick="showThresholdModal()">
<i class="fas fa-bell"></i>
<span>Notification Thresholds</span>
</button>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
</div>
<div id="agentConfirmModal" class="modal">
<div class="modal-dialog">
<div class="modal-header">
<h3 id="agentModalTitle">Install Monitoring Agent</h3>
<button type="button" class="modal-close" onclick="closeAgentModal()">&times;</button>
</div>
<div class="modal-body">
<p id="agentModalMessage">
This will install the monitoring agent on <strong><?= htmlspecialchars($server['name'] ?? '') ?></strong> via SSH.
</p>
<p class="text-muted">
The agent will run as a systemd service, collecting and sending metrics every 60 seconds.
It will automatically restart if the server reboots.
</p>
</div>
<div class="modal-footer">
<button id="agentModalConfirmBtn" class="btn btn-primary" onclick="confirmAgentAction()">Install</button>
<button class="btn btn-secondary" onclick="closeAgentModal()">Cancel</button>
</div>
</div>
</div>
<div id="thresholdModal" class="modal">
<div class="modal-dialog" style="max-width:560px">
<div class="modal-header">
<h3><i class="fas fa-bell"></i> Notification Thresholds</h3>
<button type="button" class="modal-close" onclick="closeThresholdModal()">&times;</button>
</div>
<div class="modal-body">
<p class="text-muted" style="margin-bottom:24px;font-size:0.9em;line-height:1.5">
When the agent reports values above these thresholds, all users with access to this server
receive a notification and push alert. Only the server owner can modify them.
</p>
<form id="thresholdForm" onsubmit="return false">
<?php $resources = [
'cpu' => ['label' => 'CPU', 'icon' => 'fas fa-microchip', 'color' => 'var(--info)'],
'ram' => ['label' => 'RAM', 'icon' => 'fas fa-memory', 'color' => 'var(--purple)'],
'disk' => ['label' => 'Disk', 'icon' => 'fas fa-hdd', 'color' => 'var(--warning)'],
]; ?>
<?php foreach ($resources as $key => $res): ?>
<div style="background:var(--card-bg);border:1px solid var(--border);border-radius:10px;padding:16px 20px;margin-bottom:12px">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:16px">
<i class="<?= $res['icon'] ?>" style="color:<?= $res['color'] ?>;font-size:1.2em;width:20px;text-align:center"></i>
<strong style="font-size:1em"><?= $res['label'] ?></strong>
</div>
<div style="display:flex;gap:24px;align-items:flex-start">
<div style="flex:1">
<label style="display:flex;align-items:center;gap:6px;font-size:0.82em;color:var(--warning);margin-bottom:6px;font-weight:600">
<i class="fas fa-exclamation-triangle" style="font-size:0.85em"></i> Warning
</label>
<div style="display:flex;align-items:center;gap:10px">
<input type="range" name="<?= $key ?>_warning"
value="<?= htmlspecialchars((string)($server["threshold_{$key}_warning"] ?? 80)) ?>"
min="0" max="100" step="0.5"
oninput="document.getElementById('<?= $key ?>_warn_val').textContent = this.value + '%'"
style="flex:1;height:6px;-webkit-appearance:none;appearance:none;border-radius:3px;background:linear-gradient(to right, var(--success), var(--warning) 50%, var(--danger) 80%);outline:none;cursor:pointer">
<span id="<?= $key ?>_warn_val" style="min-width:52px;font-size:0.95em;font-weight:700;color:var(--warning);text-align:right"><?= htmlspecialchars((string)($server["threshold_{$key}_warning"] ?? 80)) ?>%</span>
</div>
</div>
<div style="flex:1">
<label style="display:flex;align-items:center;gap:6px;font-size:0.82em;color:var(--danger);margin-bottom:6px;font-weight:600">
<i class="fas fa-bolt" style="font-size:0.85em"></i> Critical
</label>
<div style="display:flex;align-items:center;gap:10px">
<input type="range" name="<?= $key ?>_critical"
value="<?= htmlspecialchars((string)($server["threshold_{$key}_critical"] ?? 95)) ?>"
min="0" max="100" step="0.5"
oninput="document.getElementById('<?= $key ?>_crit_val').textContent = this.value + '%'"
style="flex:1;height:6px;-webkit-appearance:none;appearance:none;border-radius:3px;background:linear-gradient(to right, var(--success), var(--warning) 50%, var(--danger) 80%);outline:none;cursor:pointer">
<span id="<?= $key ?>_crit_val" style="min-width:52px;font-size:0.95em;font-weight:700;color:var(--danger);text-align:right"><?= htmlspecialchars((string)($server["threshold_{$key}_critical"] ?? 95)) ?>%</span>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-primary" onclick="saveThresholds()"><i class="fas fa-save"></i> Save Thresholds</button>
<button class="btn btn-secondary" onclick="closeThresholdModal()">Cancel</button>
</div>
</div>
</div>
<form id="csrfForm" style="display:none">
<input type="hidden" name="_csrf_token" value="<?= $this->csrfToken() ?>">
</form>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
<script>const historicalData = <?= json_encode($historicalMetrics, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES) ?>;</script>
<script>
const serverId = <?= $server['id'] ?>;
const serverName = '<?= addslashes($server['name'] ?? '') ?>';
</script>
<script src="/assets/js/server-show.js"></script>