web_plsql
Version:
The Express Middleware for Oracle PL/SQL
517 lines (503 loc) • 21.5 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>web_plsql Admin Console</title>
<link rel="icon" type="image/svg+xml" href="/admin/assets/favicon-mQAM4tVu.svg" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
<script type="module" crossorigin src="/admin/assets/main-C8GKnEhz.js"></script>
<link rel="stylesheet" crossorigin href="/admin/assets/main-bU4x_yEW.css">
</head>
<body class="dark">
<div class="app-container">
<aside class="sidebar">
<div class="logo">
<span class="material-symbols-rounded">database</span>
<div style="display: flex; flex-direction: column; line-height: 1">
<span>web_plsql</span>
<small id="sidebar-version" style="font-size: 0.65rem; opacity: 0.7; margin-top: 2px"></small>
</div>
</div>
<nav>
<button data-view="overview" class="active">
<span class="material-symbols-rounded">dashboard</span>
Overview
</button>
<button data-view="trace">
<span class="material-symbols-rounded">bolt</span>
Requests
</button>
<button data-view="errors">
<span class="material-symbols-rounded">error</span>
Errors
</button>
<button data-view="access">
<span class="material-symbols-rounded">list_alt</span>
Access Log
</button>
<button data-view="pools">
<span class="material-symbols-rounded">database</span>
Pools
</button>
<button data-view="stats">
<span class="material-symbols-rounded">query_stats</span>
Stats
</button>
<button data-view="config">
<span class="material-symbols-rounded">settings</span>
Configuration
</button>
<button data-view="system">
<span class="material-symbols-rounded">terminal</span>
System
</button>
</nav>
<div class="status-indicator">
<span id="server-status-dot" class="dot"></span>
<span id="server-status-text">Checking...</span>
</div>
</aside>
<main class="content">
<header class="main-header">
<h1 id="view-title"><span class="material-symbols-rounded">dashboard</span>Overview</h1>
<div class="header-toolbar">
<div class="auto-refresh-group">
<label for="auto-refresh-toggle">Auto-refresh</label>
<input type="checkbox" id="auto-refresh-toggle" checked />
<select id="refresh-interval">
<option value="1000">1s</option>
<option value="5000">5s</option>
<option value="10000" selected>10s</option>
<option value="30000">30s</option>
<option value="60000">1m</option>
</select>
<button
id="manual-refresh"
class="icon-btn icon-sm"
title="Refresh Now"
style="border: none; background: none; padding: 0; min-width: auto; min-height: auto; margin-left: 4px"
>
<span class="material-symbols-rounded" style="font-size: 20px">refresh</span>
</button>
</div>
<button id="theme-toggle-btn" class="icon-btn" title="Toggle Theme">
<span class="material-symbols-rounded">dark_mode</span>
</button>
</div>
</header>
<section id="view-overview" class="view">
<div class="metrics-grid">
<div class="card" title="Time since the server started">
<div class="card-header">
<span class="material-symbols-rounded">schedule</span>
<h3 title="Time since the server started">Uptime</h3>
</div>
<p id="uptime-val" title="Total uptime duration">0s</p>
<small id="start-time-val" title="Exact server start time">-</small>
</div>
<div class="card" title="Request throughput and response times">
<div class="card-header">
<span class="material-symbols-rounded">swap_vert</span>
<h3 title="Request throughput and response times">Requests</h3>
</div>
<div class="flex items-baseline gap-1 mb-2" title="Current and maximum requests per second">
<span id="req-per-sec" class="text-2xl font-bold text-bright">0.00</span>
<span class="text-xs text-main font-medium uppercase mr-2">cur /s</span>
<span class="text-main opacity-30 mr-2">/</span>
<span id="max-req-per-sec" class="text-2xl font-bold text-bright">0.00</span>
<span class="text-xs text-main font-medium uppercase">max /s</span>
</div>
<div class="flex gap-4">
<small class="text-main" title="Average response time">Avg: <span id="avg-resp-time" class="font-bold">0ms</span></small>
<small class="text-main" title="Maximum response time">Max: <span id="max-resp-time" class="font-bold">0ms</span></small>
</div>
</div>
<div class="card" title="Total number of requests that resulted in an error">
<div class="card-header">
<span class="material-symbols-rounded">report</span>
<h3 title="Total number of requests that resulted in an error">Errors</h3>
</div>
<p id="err-count" title="Total error count">0</p>
</div>
<div class="card" title="Efficiency of the internal cache">
<div class="card-header">
<span class="material-symbols-rounded">cached</span>
<h3 title="Efficiency of the internal cache">Cache Hit Rate</h3>
</div>
<p id="cache-hit-rate-val" title="Percentage of requests served from cache">0%</p>
<small
><span id="cache-hits-val" title="Total cache hits">0</span> hits,
<span id="cache-misses-val" title="Total cache misses">0</span> misses</small
>
</div>
</div>
<div class="card" style="grid-column: span 2">
<div class="card-header">
<span class="material-symbols-rounded">monitoring</span>
<h3>TRAFFIC</h3>
<div class="header-toolbar ml-auto">
<select
id="chart-history-points"
class="btn-sm"
style="
background: var(--bg-hover);
border: 1px solid var(--border);
border-radius: 4px;
color: var(--text-main);
font-size: 0.75rem;
padding: 2px 4px;
"
>
<option value="60">Last 1 min</option>
<option value="300">Last 5 min</option>
<option value="600" selected>Last 10 min</option>
<option value="1800">Last 30 min</option>
<option value="3600">Last 1 hour</option>
<option value="7200">Last 2 hours</option>
<option value="43200">Last 12 hours</option>
<option value="86400">Last 24 hours</option>
</select>
</div>
</div>
<div class="chart-container">
<canvas id="traffic-chart"></canvas>
</div>
</div>
</section>
<section id="view-pools" class="view" style="display: none">
<div id="pools-container" class="pools-grid"></div>
<div class="card">
<div class="card-header">
<span class="material-symbols-rounded">analytics</span>
<h3>Pool Usage History</h3>
</div>
<div class="chart-container">
<canvas id="pool-chart"></canvas>
</div>
</div>
</section>
<section id="view-errors" class="view" style="display: none">
<div class="header-toolbar mb-4" style="justify-content: flex-start; gap: 12px">
<div class="search-group" style="flex: 1; max-width: 400px">
<span
class="material-symbols-rounded"
style="position: absolute; left: 8px; top: 50%; transform: translateY(-50%); font-size: 18px; opacity: 0.5"
>search</span
>
<input
type="text"
id="error-filter"
placeholder="Filter errors (URL, message, method)..."
class="input-sm"
style="width: 100%; padding-left: 32px"
/>
</div>
<div class="flex items-center gap-2">
<label for="error-limit" class="text-xs text-main">Max entries:</label>
<input type="number" id="error-limit" value="100" min="1" max="5000" class="input-sm" style="width: 100px" />
</div>
<button id="error-load-btn" class="btn btn-sm btn-primary">
<span class="material-symbols-rounded" style="font-size: 18px">refresh</span>
Load Errors
</button>
</div>
<div class="table-container">
<table id="errors-table">
<thead></thead>
<tbody></tbody>
</table>
</div>
</section>
<section id="view-trace" class="view" style="display: none">
<div class="header-toolbar mb-4" style="justify-content: flex-start; gap: 12px">
<div class="search-group" style="flex: 1; max-width: 300px">
<span
class="material-symbols-rounded"
style="position: absolute; left: 8px; top: 50%; transform: translateY(-50%); font-size: 18px; opacity: 0.5"
>search</span
>
<input type="text" id="trace-filter" placeholder="Filter traces..." class="input-sm" style="width: 100%; padding-left: 32px" />
</div>
<div class="flex items-center gap-2">
<label for="trace-limit" class="text-xs text-main">Max entries:</label>
<input type="number" id="trace-limit" value="100" min="1" max="5000" class="input-sm" style="width: 80px" />
</div>
<button id="trace-load-btn" class="btn btn-sm btn-primary">
<span class="material-symbols-rounded" style="font-size: 18px">refresh</span>
Refresh
</button>
<button id="trace-clear-btn" class="btn btn-sm btn-danger">
<span class="material-symbols-rounded" style="font-size: 18px">delete</span>
Clear
</button>
<button
id="trace-status-toggle"
class="btn btn-sm px-4 py-2 rounded-lg text-sm font-bold transition-colors bg-white/10 text-white hover:bg-white/20"
>
Tracing: OFF
</button>
</div>
<div class="table-container">
<table id="trace-table">
<thead></thead>
<tbody></tbody>
</table>
</div>
</section>
<section id="view-access" class="view" style="display: none">
<div class="header-toolbar mb-4" style="justify-content: flex-start; gap: 12px">
<div class="search-group" style="flex: 1; max-width: 400px">
<span
class="material-symbols-rounded"
style="position: absolute; left: 8px; top: 50%; transform: translateY(-50%); font-size: 18px; opacity: 0.5"
>search</span
>
<input type="text" id="access-filter" placeholder="Filter logs..." class="input-sm" style="width: 100%; padding-left: 32px" />
</div>
<div class="flex items-center gap-2">
<label for="access-limit" class="text-xs text-main">Max entries:</label>
<input type="number" id="access-limit" value="100" min="1" max="5000" class="input-sm" style="width: 100px" />
</div>
<button id="access-load-btn" class="btn btn-sm btn-primary">
<span class="material-symbols-rounded" style="font-size: 18px">refresh</span>
Load Logs
</button>
<small id="access-log-range" class="text-main" style="margin-left: auto">No logs loaded</small>
</div>
<div class="terminal-container">
<pre id="access-log-view" class="terminal" title="Real-time access logs from the server"></pre>
</div>
</section>
<section id="view-stats" class="view" style="display: none">
<div class="header-toolbar mb-4" style="justify-content: flex-start; gap: 12px">
<div class="flex items-center gap-2">
<label for="stats-limit" class="text-xs text-main">Max entries:</label>
<input type="number" id="stats-limit" value="50" min="1" max="1000" class="input-sm" style="width: 80px" />
</div>
<button id="stats-load-btn" class="btn btn-sm btn-primary">
<span class="material-symbols-rounded" style="font-size: 18px">refresh</span>
Load Stats
</button>
<small id="stats-history-info" class="text-main" style="margin-left: auto">No stats loaded</small>
</div>
<div class="table-container">
<table id="stats-table">
<thead>
<tr>
<th title="Timestamp of the interval">Timestamp</th>
<th title="Requests in this interval" class="text-center">Req</th>
<th title="Errors in this interval" class="text-center">Err</th>
<th title="Min Latency (ms)" class="text-right">Min</th>
<th title="Avg Latency (ms)" class="text-right">Avg</th>
<th title="95th Percentile Latency (ms)" class="text-right">P95</th>
<th title="99th Percentile Latency (ms)" class="text-right">P99</th>
<th title="Max Latency (ms)" class="text-right">Max</th>
<th title="CPU Usage (%)" class="text-right">CPU %</th>
<th title="Resident Set Size (MB)" class="text-right">RSS</th>
<th title="Heap Used (MB)" class="text-right">Heap</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</section>
<section id="view-config" class="view" style="display: none">
<div id="config-view"></div>
</section>
<section id="view-system" class="view view-system-compact" style="display: none">
<div class="metrics-grid mb-4">
<div class="card">
<div class="card-header">
<span class="material-symbols-rounded">info</span>
<h3>Server Information</h3>
</div>
<div class="text-sm text-main">
<div class="stat-row">
<span>Middleware Version</span>
<span id="middleware-version" class="font-mono text-accent font-bold">-</span>
</div>
<div class="stat-row">
<span>Node.js Version</span>
<span id="node-version" class="font-mono text-accent font-bold">-</span>
</div>
<div class="stat-row">
<span>Platform</span>
<span id="platform-info" class="text-accent font-bold">-</span>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<span class="material-symbols-rounded">schedule</span>
<h3>Runtime</h3>
</div>
<div class="text-sm text-main">
<div class="stat-row">
<span>Server Uptime</span>
<span id="system-uptime" class="text-accent font-bold">-</span>
</div>
<div class="stat-row">
<span>Start Time</span>
<span id="system-start-time" class="text-accent font-bold">-</span>
</div>
<div class="stat-row">
<span>Status</span>
<span id="system-status" class="status-dot">
<span class="dot running"></span>
<span id="system-status-text" class="text-accent font-bold">-</span>
</span>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<span class="material-symbols-rounded">insights</span>
<h3>Activity</h3>
</div>
<div class="text-sm text-main">
<div class="stat-row">
<span>Total Requests</span>
<span id="total-requests" class="font-mono text-accent font-bold">-</span>
</div>
<div class="stat-row">
<span>Total Errors</span>
<span id="total-errors" class="font-mono text-danger font-bold">-</span>
</div>
<div class="stat-row">
<span>Active Pools</span>
<span id="active-pools" class="font-mono text-accent font-bold">-</span>
</div>
</div>
</div>
</div>
<div class="metrics-grid">
<div class="card resource-card" title="Memory usage statistics for the Node.js process">
<div class="card-header">
<span class="material-symbols-rounded">memory</span>
<h3 title="Memory usage statistics for the Node.js process">Memory Usage</h3>
</div>
<div class="stat-container-wrapper text-sm text-main">
<div class="stat-container">
<div class="stat-row">
<span>Memory Usage (%)</span>
<span id="memory-percent" class="font-mono text-accent font-bold">-</span>
</div>
<div class="stat-row" title="Memory currently used by Node.js objects">
<span>Heap Used</span>
<div class="stat-values">
<span id="memory-heap-used" class="font-mono text-accent font-bold">-</span>
<small class="min-max">max: <span id="memory-heap-used-max">-</span></small>
</div>
</div>
<div class="stat-row" title="Total memory allocated for the heap">
<span>Heap Total</span>
<div class="stat-values">
<span id="memory-heap-total" class="font-mono text-accent font-bold">-</span>
<small class="min-max">max: <span id="memory-heap-total-max">-</span></small>
</div>
</div>
<div class="stat-row" title="Resident Set Size - total memory used by the process">
<span>RSS</span>
<div class="stat-values">
<span id="memory-rss" class="font-mono text-accent font-bold">-</span>
<small class="min-max">max: <span id="memory-rss-max">-</span></small>
</div>
</div>
</div>
</div>
<div class="chart-container-mini">
<canvas id="memory-chart"></canvas>
</div>
</div>
<div class="card resource-card" title="CPU time consumed by the process">
<div class="card-header">
<span class="material-symbols-rounded">speed</span>
<h3 title="CPU time consumed by the process">CPU Usage</h3>
</div>
<div class="stat-container-wrapper text-sm text-main">
<div class="stat-container">
<div class="stat-row">
<span>CPU Usage (%)</span>
<span id="cpu-percent" class="font-mono text-accent font-bold">-</span>
</div>
<div class="stat-row" title="Time spent in user code">
<span>User</span>
<div class="stat-values">
<span id="cpu-user" class="font-mono text-accent font-bold">-</span>
<small class="min-max">max: <span id="cpu-user-max">-</span></small>
</div>
</div>
<div class="stat-row" title="Time spent in system (kernel) code">
<span>System</span>
<div class="stat-values">
<span id="cpu-system" class="font-mono text-accent font-bold">-</span>
<small class="min-max">max: <span id="cpu-system-max">-</span></small>
</div>
</div>
<div class="stat-row">
<span>Hardware</span>
<span id="cpu-cores-info" class="text-accent font-bold">-</span>
</div>
</div>
</div>
<div class="chart-container-mini">
<canvas id="cpu-chart"></canvas>
</div>
</div>
</div>
<div class="card danger-zone">
<h3 class="danger-zone-title">Danger Zone</h3>
<div style="display: flex; gap: 12px; margin-top: 16px">
<button id="btn-clear-all-cache" class="btn btn-sm btn-warning">Clear All Caches</button>
<button id="btn-pause" class="btn btn-sm btn-warning">Pause Server</button>
<button id="btn-resume" class="btn btn-sm btn-success" style="display: none">Resume Server</button>
<button id="btn-stop" class="btn btn-sm btn-danger">Stop Server</button>
</div>
</div>
</section>
</main>
</div>
<div id="error-modal" class="modal" style="display: none">
<div class="modal-content">
<div class="modal-header">
<h3>Error Details</h3>
<button class="icon-btn" onclick="document.getElementById('error-modal').style.display = 'none'">
<span class="material-symbols-rounded">close</span>
</button>
</div>
<div class="modal-body">
<pre id="error-detail-content" class="terminal" style="max-height: 70vh; overflow: auto"></pre>
</div>
</div>
</div>
<div id="trace-modal" class="modal" style="display: none">
<div class="modal-content">
<div class="modal-header">
<h3>Trace Details</h3>
<button class="icon-btn" onclick="document.getElementById('trace-modal').style.display = 'none'">
<span class="material-symbols-rounded">close</span>
</button>
</div>
<div class="modal-body">
<pre id="trace-detail-content" class="terminal" style="max-height: 70vh; overflow: auto"></pre>
</div>
</div>
</div>
<div id="offline-modal" class="modal" style="display: none">
<div class="modal-content" style="max-width: 400px; text-align: center">
<div class="modal-body" style="display: flex; flex-direction: column; align-items: center; gap: 16px; padding: 32px">
<span class="material-symbols-rounded" style="font-size: 48px; color: var(--danger)">wifi_off</span>
<h3 style="margin: 0; font-size: 1.25rem; color: var(--text-bright)">Connection Lost</h3>
<p style="margin: 0; color: var(--text-main)">The server is unreachable. Please check your connection or server status.</p>
<p id="offline-countdown" style="margin: 0; color: var(--text-main); font-size: 0.875rem"></p>
<button id="btn-reconnect" class="btn btn-primary btn-lg w-full justify-center">
<span id="reconnect-icon" class="material-symbols-rounded">refresh</span>
<span id="reconnect-spinner" class="material-symbols-rounded animate-spin" style="display: none">sync</span>
<span id="reconnect-text">Try Reconnect</span>
</button>
</div>
</div>
</div>
</body>
</html>