web_plsql 1.0.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/README.md +108 -13
  2. package/dist/chunk-DQk6qfdC.mjs +18 -0
  3. package/dist/frontend/assets/main-0oxRTIkL.js +147 -0
  4. package/dist/frontend/assets/main-0oxRTIkL.js.br +0 -0
  5. package/dist/frontend/assets/main-0oxRTIkL.js.gz +0 -0
  6. package/dist/frontend/assets/main-TYgLak6O.css +1 -0
  7. package/dist/frontend/assets/main-TYgLak6O.css.br +0 -0
  8. package/dist/frontend/assets/main-TYgLak6O.css.gz +0 -0
  9. package/dist/frontend/index.html +516 -0
  10. package/dist/frontend/index.html.br +0 -0
  11. package/dist/frontend/index.html.gz +0 -0
  12. package/dist/index.d.mts +646 -0
  13. package/dist/index.mjs +3548 -0
  14. package/dist/index.mjs.map +1 -0
  15. package/dist/oracledb-mock-Dn8aHtd7.mjs +68 -0
  16. package/dist/oracledb-mock-Dn8aHtd7.mjs.map +1 -0
  17. package/examples/config-apex.js +1 -1
  18. package/examples/config-docker.js +1 -2
  19. package/package.json +45 -32
  20. package/examples/config-native.js +0 -68
  21. package/src/admin/client/charts.ts +0 -299
  22. package/src/admin/client/main.js +0 -3
  23. package/src/admin/client/tailwind.css +0 -41
  24. package/src/admin/index.html +0 -315
  25. package/src/admin/js/api.ts +0 -95
  26. package/src/admin/js/app.ts +0 -306
  27. package/src/admin/js/eslint.config.js +0 -74
  28. package/src/admin/js/schemas.ts +0 -153
  29. package/src/admin/js/templates/config.ts +0 -146
  30. package/src/admin/js/templates/errorRow.ts +0 -18
  31. package/src/admin/js/templates/index.ts +0 -3
  32. package/src/admin/js/templates/poolCard.ts +0 -61
  33. package/src/admin/js/tsconfig.json +0 -24
  34. package/src/admin/js/types.ts +0 -223
  35. package/src/admin/js/ui/theme.ts +0 -93
  36. package/src/admin/js/ui/views.ts +0 -164
  37. package/src/admin/js/util/format.ts +0 -27
  38. package/src/admin/lib/assets/main-zpdhQ1gD.css +0 -1
  39. package/src/admin/lib/chart.bundle.js +0 -139
  40. package/src/admin/style.css +0 -1321
  41. package/src/bin/load-test.js +0 -202
  42. package/src/handler/handlerAdmin.js +0 -198
  43. package/src/handler/handlerLogger.js +0 -21
  44. package/src/handler/handlerMetrics.js +0 -68
  45. package/src/handler/handlerUpload.js +0 -26
  46. package/src/handler/plsql/cgi.js +0 -131
  47. package/src/handler/plsql/errorPage.js +0 -117
  48. package/src/handler/plsql/handlerPlSql.js +0 -90
  49. package/src/handler/plsql/parsePage.js +0 -213
  50. package/src/handler/plsql/procedure.js +0 -356
  51. package/src/handler/plsql/procedureError.js +0 -40
  52. package/src/handler/plsql/procedureNamed.js +0 -268
  53. package/src/handler/plsql/procedureSanitize.js +0 -262
  54. package/src/handler/plsql/procedureVariable.js +0 -54
  55. package/src/handler/plsql/request.js +0 -124
  56. package/src/handler/plsql/requestError.js +0 -23
  57. package/src/handler/plsql/sendResponse.js +0 -136
  58. package/src/handler/plsql/stream.js +0 -28
  59. package/src/handler/plsql/upload.js +0 -109
  60. package/src/index.js +0 -20
  61. package/src/server/config.js +0 -57
  62. package/src/server/connections.js +0 -40
  63. package/src/server/server.js +0 -289
  64. package/src/types.js +0 -150
  65. package/src/util/cache.js +0 -123
  66. package/src/util/errorToString.js +0 -24
  67. package/src/util/file.js +0 -91
  68. package/src/util/html.js +0 -53
  69. package/src/util/jsonLogger.js +0 -47
  70. package/src/util/oracle.js +0 -80
  71. package/src/util/shutdown.js +0 -44
  72. package/src/util/trace.js +0 -325
  73. package/src/util/type.js +0 -6
  74. package/src/util/util.js +0 -66
  75. package/src/version.js +0 -5
  76. package/types/handler/handlerAdmin.d.ts +0 -9
  77. package/types/handler/handlerLogger.d.ts +0 -2
  78. package/types/handler/handlerMetrics.d.ts +0 -25
  79. package/types/handler/handlerUpload.d.ts +0 -7
  80. package/types/handler/plsql/cgi.d.ts +0 -4
  81. package/types/handler/plsql/errorPage.d.ts +0 -11
  82. package/types/handler/plsql/handlerPlSql.d.ts +0 -13
  83. package/types/handler/plsql/parsePage.d.ts +0 -3
  84. package/types/handler/plsql/procedure.d.ts +0 -12
  85. package/types/handler/plsql/procedureError.d.ts +0 -23
  86. package/types/handler/plsql/procedureNamed.d.ts +0 -14
  87. package/types/handler/plsql/procedureSanitize.d.ts +0 -11
  88. package/types/handler/plsql/procedureVariable.d.ts +0 -10
  89. package/types/handler/plsql/request.d.ts +0 -9
  90. package/types/handler/plsql/requestError.d.ts +0 -8
  91. package/types/handler/plsql/sendResponse.d.ts +0 -6
  92. package/types/handler/plsql/upload.d.ts +0 -5
  93. package/types/index.d.ts +0 -11
  94. package/types/server/config.d.ts +0 -2
  95. package/types/server/server.d.ts +0 -74
  96. package/types/types.d.ts +0 -328
  97. package/types/util/cache.d.ts +0 -69
  98. package/types/util/errorToString.d.ts +0 -1
  99. package/types/util/file.d.ts +0 -6
  100. package/types/util/html.d.ts +0 -3
  101. package/types/util/jsonLogger.d.ts +0 -45
  102. package/types/util/oracle.d.ts +0 -5
  103. package/types/util/shutdown.d.ts +0 -2
  104. package/types/util/trace.d.ts +0 -22
  105. package/types/util/type.d.ts +0 -1
  106. package/types/util/util.d.ts +0 -3
  107. package/types/version.d.ts +0 -1
  108. /package/{src/admin/favicon.svg → dist/frontend/assets/favicon-mQAM4tVu.svg} +0 -0
@@ -0,0 +1 @@
1
+ :root{--accent-rgb: 59, 130, 246;--bg-main: #f8fafc;--bg-side: #fff;--bg-card: #fff;--bg-hover: #f1f5f9;--text-main: #475569;--text-bright: #0f172a;--accent: #3b82f6;--border: #e2e8f0;--success: #10b981;--warning: #f59e0b;--danger: #ef4444;--shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--terminal-bg: #1e293b;--config-key: #3b82f6}body.dark{--bg-main: #0f172a;--bg-side: #1e293b;--bg-card: #1e293b;--bg-hover: #334155;--text-main: #94a3b8;--text-bright: #f8fafc;--accent: #3b82f6;--border: #334155;--success: #10b981;--warning: #f59e0b;--danger: #ef4444;--shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--terminal-bg: #000;--config-key: #60a5fa}body{margin:0;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background-color:var(--bg-main);color:var(--text-main);-webkit-font-smoothing:antialiased;transition:background-color .3s,color .3s}.app-container{display:flex;height:100vh}.sidebar{width:240px;background-color:var(--bg-side);border-right:1px solid var(--border);display:flex;flex-direction:column;z-index:10}.logo{padding:24px;font-weight:700;font-size:1.25rem;color:var(--text-bright);display:flex;align-items:center;gap:12px}.logo .material-symbols-rounded{color:var(--accent);font-size:28px}nav{flex:1;padding:12px}.status-indicator{padding:20px;border-top:1px solid var(--border);display:flex;align-items:center;font-size:.85rem;font-weight:500}.dot{height:8px;width:8px;background-color:#64748b;border-radius:50%;display:inline-block;margin-right:12px;box-shadow:0 0 0 4px #64748b1a}.dot.running{background-color:var(--success);box-shadow:0 0 0 4px #10b98133}.dot.paused{background-color:var(--warning);box-shadow:0 0 0 4px #f59e0b33}.content{flex:1;display:flex;flex-direction:column;overflow:hidden}.main-header{padding:20px 32px;background-color:var(--bg-main);border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}.main-header h1{margin:0;font-size:1.5rem;color:var(--text-bright);font-weight:600;display:flex;align-items:center;gap:12px}.main-header h1 .material-symbols-rounded{color:var(--accent);font-size:28px}.header-toolbar{display:flex;align-items:center;gap:24px}.auto-refresh-group{display:flex;align-items:center;gap:12px;font-size:.875rem;background:var(--bg-side);padding:6px 12px;border-radius:6px;border:1px solid var(--border)}.auto-refresh-group select{background:none;border:none;color:var(--text-bright);cursor:pointer;font-weight:500}.view{flex:1;padding:32px;overflow-y:auto}.metrics-grid,.pools-grid,.cache-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:24px;margin-bottom:32px}.card{background-color:var(--bg-card);padding:24px;border-radius:12px;border:1px solid var(--border);box-shadow:var(--shadow)}.card-header{display:flex;align-items:center;gap:12px;margin-bottom:16px}.card-header .material-symbols-rounded{color:var(--accent)}.card h3{margin:0;font-size:.875rem;text-transform:uppercase;letter-spacing:.05em;color:var(--text-main)}.card p{font-size:2rem;font-weight:700;margin:0;color:var(--text-bright)}.card small{display:block;margin-top:8px;font-size:.875rem;color:var(--text-main)}.card.warning{border-left:4px solid var(--warning)}.table-container{background:var(--bg-card);border-radius:12px;border:1px solid var(--border);overflow:hidden;box-shadow:var(--shadow)}table{width:100%;border-collapse:collapse}th,td{padding:16px 24px;text-align:left;border-bottom:1px solid var(--border)}th{background-color:var(--bg-hover);color:var(--text-main);font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;font-weight:600}td{color:var(--text-bright);font-size:.9375rem}tr:last-child td{border-bottom:none}.terminal-container,.config-container{background-color:var(--bg-side);border-radius:12px;border:1px solid var(--border);overflow:hidden;box-shadow:var(--shadow)}.terminal{background-color:var(--terminal-bg);color:#10b981;padding:24px;font-family:JetBrains Mono,Fira Code,monospace;font-size:.875rem;line-height:1.6;margin:0;overflow-x:auto;white-space:pre}.config-view-content{padding:0;max-width:900px;margin:0 auto}.config-table{width:100%;border-collapse:collapse}.config-table tr{border-bottom:1px solid var(--border)}.config-table tr:last-child{border-bottom:none}.config-table td{padding:16px 24px;vertical-align:top}.config-label{font-weight:600;color:var(--text-main);width:240px;font-size:.875rem;background-color:var(--bg-main)}.config-value{font-family:JetBrains Mono,monospace;color:var(--text-bright);word-break:break-all;font-size:.875rem}.config-section-header{background-color:var(--bg-hover);padding:12px 24px;font-weight:700;font-size:.75rem;text-transform:uppercase;color:var(--accent);letter-spacing:.05em;border-bottom:1px solid var(--border)}.inner-config-table{width:100%;border-collapse:collapse;font-size:.8125rem}.inner-config-table td{padding:4px 8px;border:none}.cache-card .badge{align-self:center}.card-header h4{color:var(--accent)}.stat-row-label{flex:0 0 180px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.stat-row-value{flex:1;text-align:right}@media(max-width:640px){.stat-row{flex-direction:column;align-items:flex-start;gap:4px}.stat-row-label{flex:none;opacity:.7;font-size:.75rem;text-align:left}.stat-row-value{text-align:left;width:100%}}.view-system-compact{padding:20px 32px}.view-system-compact .metrics-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px;align-items:start;margin-bottom:24px}.view-system-compact .card{padding:16px}.view-system-compact .stat-row{padding:4px 0}.view-system-compact .card-header{margin-bottom:12px}.resource-card{display:flex;flex-direction:column;min-height:350px}.resource-card .chart-container-mini{margin-top:auto}.chart-container-mini{height:100px;width:100%;position:relative;overflow:hidden;border:none;border-radius:4px}.chart-container{margin-bottom:32px;height:300px;position:relative}.btn,.icon-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:10px 20px;border-radius:8px;font-weight:600;font-size:.875rem;cursor:pointer;border:none;transition:all .2s;background-color:var(--bg-hover);color:var(--text-bright)}.btn .material-symbols-rounded,.icon-btn .material-symbols-rounded{font-size:18px}.btn:hover,.icon-btn:hover{background-color:var(--border)}.btn-primary{background-color:var(--accent);color:#fff}.btn-primary:hover{opacity:.9;background-color:var(--accent)}.btn-success{background-color:var(--success);color:#fff}.btn-success:hover{opacity:.9}.btn-warning{background-color:var(--warning);color:#000}.btn-warning:hover{opacity:.9}.btn-danger{background-color:var(--danger);color:#fff}.btn-danger:hover{opacity:.9}.btn-outline{background:transparent;border:1px solid var(--border);color:var(--accent)}.btn-outline:hover{background-color:var(--bg-hover)}.btn-full{width:100%}.btn-sm{padding:6px 12px;font-size:.8125rem}.btn-sm .material-symbols-rounded{font-size:16px}.btn-lg{padding:14px 28px;font-size:1rem}.btn-lg .material-symbols-rounded{font-size:22px}nav button{width:100%;padding:12px 16px;text-align:left;background:none;border:none;color:var(--text-main);cursor:pointer;font-size:.95rem;display:flex;align-items:center;gap:12px;border-radius:8px;transition:all .2s;margin-bottom:4px}nav button:hover{background-color:var(--bg-hover);color:var(--text-bright)}nav button.active{background-color:var(--accent);color:#fff}nav button .material-symbols-rounded{font-size:20px}.icon-btn{padding:10px;min-width:40px;min-height:40px}.icon-btn.icon-sm{padding:6px;min-width:32px;min-height:32px}.icon-btn.icon-sm .material-symbols-rounded{font-size:20px}.control-group{display:flex;gap:16px;margin-top:24px;flex-wrap:wrap}.control-group .btn{flex:1;min-width:140px}.gap-1{gap:4px}.mt-1{margin-top:4px}.mt-2{margin-top:8px}.mt-3{margin-top:12px}.mt-4{margin-top:16px}.mt-6{margin-top:24px}.mb-1{margin-bottom:4px}.mb-2{margin-bottom:8px}.mb-3{margin-bottom:12px}.mb-4{margin-bottom:16px}.mb-6{margin-bottom:24px}.p-2{padding:8px}.p-3{padding:12px}.p-4{padding:16px}.p-6{padding:24px}.mx-auto{margin-left:auto;margin-right:auto}.flex{display:flex}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.self-center{align-self:center}.self-end{align-self:flex-end}.text-xs{font-size:.75rem}.text-sm{font-size:.875rem}.text-lg{font-size:1.125rem}.text-xl{font-size:1.25rem}.text-2xl{font-size:1.5rem}.text-3xl{font-size:1.875rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.font-bold{font-weight:700}.text-center{text-align:center}.text-right{text-align:right}.text-main{color:var(--text-main)}.text-bright{color:var(--text-bright)}.text-accent{color:var(--accent)}.text-success{color:var(--success)}.text-warning{color:var(--warning)}.text-danger{color:var(--danger)}.bg-main{background-color:var(--bg-main)}.bg-card{background-color:var(--bg-card)}.bg-hover{background-color:var(--bg-hover)}.bg-success{background-color:var(--success)}.bg-warning{background-color:var(--warning)}.bg-danger{background-color:var(--danger)}.border{border:1px solid var(--border)}.border-b{border-bottom:1px solid var(--border)}.border-none{border:none}.border-t{border-top:1px solid var(--border)}.border-l{border-left:1px solid var(--border)}.border-r{border-right:1px solid var(--border)}.rounded{border-radius:4px}.rounded-md{border-radius:6px}.rounded-lg{border-radius:8px}.rounded-xl{border-radius:12px}.rounded-full{border-radius:9999px}.shadow-sm{box-shadow:var(--shadow)}.shadow-md{box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}.w-full{width:100%}.w-auto{width:auto}.max-w-xs{max-width:120px}.max-w-sm{max-width:200px}.max-w-md{max-width:280px}.overflow-hidden{overflow:hidden}.overflow-auto{overflow:auto}.overflow-x-auto{overflow-x:auto}.cursor-pointer{cursor:pointer}.transition{transition:all .2s ease}.transition-colors{transition:background-color .2s,color .2s,border-color .2s}.transition-all{transition:all .2s ease}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.hover-bg:hover{background-color:var(--bg-hover)}.hover-border:hover{border-color:var(--accent)}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.opacity-90{opacity:.9}.leading-tight{line-height:1.25}.leading-normal{line-height:1.5}.leading-relaxed{line-height:1.625}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.break-all{word-break:break-all}.grid{display:grid}.grid-cols-2{grid-template-columns:repeat(2,1fr)}.grid-cols-3{grid-template-columns:repeat(3,1fr)}.grid-cols-auto{grid-template-columns:repeat(auto-fit,minmax(120px,1fr))}.gap-2{gap:8px}.gap-3{gap:12px}.gap-4{gap:16px}.gap-6{gap:24px}.stat-card{background-color:var(--bg-card);padding:16px;border-radius:8px;border:1px solid var(--border);text-align:center}.stat-card-value{font-size:1.75rem;font-weight:700;color:var(--text-bright);line-height:1.2}.stat-card-label{font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;color:var(--text-main);margin-top:4px}.progress-bar{height:6px;background:var(--bg-main);border-radius:3px;overflow:hidden}.progress-bar-fill{height:100%;border-radius:3px;transition:width .3s ease}.progress-bar-sm{height:4px}.progress-bar-lg{height:8px}.badge{display:inline-flex;align-items:center;padding:4px 8px;border-radius:9999px;font-size:.75rem;font-weight:600;gap:4px}.badge-success{background-color:#10b98126;color:var(--success)}.badge-warning{background-color:#f59e0b26;color:var(--warning)}.badge-danger{background-color:#ef444426;color:var(--danger)}.badge-info{background-color:#3b82f626;color:var(--accent)}.status-dot{display:inline-flex;align-items:center;gap:6px;font-size:.875rem;font-weight:500}.status-dot .dot{margin:0;flex-shrink:0}.table-row-hover tbody tr{transition:background-color .15s ease}.table-row-hover tbody tr:hover{background-color:var(--bg-hover)}.table-cell{padding:12px 16px;text-align:left;border-bottom:1px solid var(--border)}.table-cell-sm{padding:8px 12px;font-size:.8125rem}.table-header{background-color:var(--bg-hover);color:var(--text-main);font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;font-weight:600;padding:12px 16px;text-align:left}.dense-table th,.dense-table td{padding:6px 12px;font-size:.8125rem}.table-layout-auto{table-layout:auto}.table-layout-fixed{table-layout:fixed}.code{font-family:JetBrains Mono,Fira Code,monospace;font-size:.875rem;background-color:var(--bg-main);padding:2px 6px;border-radius:4px;color:var(--accent)}.code-sm{font-size:.75rem;padding:1px 4px}.description{font-size:.75rem;color:var(--text-main);font-weight:400}.stat-row{display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)}.stat-row:last-child{border-bottom:none}.stat-row-label{color:var(--text-main);font-size:.875rem}.stat-row-value{color:var(--text-bright);font-weight:600;font-family:monospace}.card-section{margin-bottom:24px}.card-section:last-child{margin-bottom:0}.card-clickable{cursor:pointer;transition:all .2s ease}.card-clickable:hover{border-color:var(--accent);box-shadow:0 4px 12px #3b82f626}.icon-xs{font-size:14px}.icon-sm{font-size:18px}.icon-md{font-size:20px}.icon-lg{font-size:24px}.icon-xl{font-size:28px}.modal{position:fixed;inset:0;background-color:#000000b3;display:flex;align-items:center;justify-content:center;z-index:1000;padding:20px}.modal-content{background-color:var(--bg-card);border-radius:12px;width:100%;max-width:900px;box-shadow:var(--shadow);display:flex;flex-direction:column;max-height:90vh}.modal-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}.modal-header h3{margin:0;font-size:1.125rem;color:var(--text-bright)}.modal-body{padding:24px;overflow-y:auto}.stat-values-inline{display:flex;align-items:center;gap:8px}.stat-values{display:flex;flex-direction:column;align-items:flex-end}.min-max{font-size:.7rem;opacity:.7;margin-top:2px}.search-group{position:relative;display:flex;align-items:center}.input-sm{background-color:var(--bg-side);border:1px solid var(--border);border-radius:6px;color:var(--text-bright);padding:6px 12px;font-size:.875rem}.input-sm:focus{border-color:var(--accent);outline:none}.errors-table-row{cursor:pointer;transition:background-color .2s}.errors-table-row:hover{background-color:rgba(var(--accent-rgb),.08)}.server-status{display:flex;align-items:center;gap:8px;padding:8px 12px;background-color:var(--bg-card);border-radius:8px;border:1px solid var(--border)}.server-status-indicator{display:flex;align-items:center;gap:8px}.server-status-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0}.server-status-dot.running{background-color:var(--success);box-shadow:0 0 8px #10b98166}.server-status-dot.paused{background-color:var(--warning);box-shadow:0 0 8px #f59e0b66}.server-status-dot.stopped{background-color:var(--danger);box-shadow:0 0 8px #ef444466}.server-status-text{font-size:.875rem;font-weight:500;text-transform:uppercase;letter-spacing:.025em}.danger-zone{border:1px solid var(--warning);border-left-width:4px;background-color:#f59e0b08}.danger-zone-title{color:var(--warning);font-weight:600;margin-bottom:8px}.empty-state{text-align:center;padding:48px 24px;color:var(--text-main)}.empty-state-icon{font-size:48px;color:var(--text-main);opacity:.5;margin-bottom:16px}.empty-state-text{font-size:.875rem}.skeleton{background:linear-gradient(90deg,var(--bg-main) 25%,var(--bg-hover) 50%,var(--bg-main) 75%);background-size:200% 100%;animation:skeleton-loading 1.5s infinite;border-radius:4px}@keyframes skeleton-loading{0%{background-position:200% 0}to{background-position:-200% 0}}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--bg-main)}::-webkit-scrollbar-thumb{background:var(--border);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--text-main);opacity:.5}button:focus-visible,input:focus-visible,select:focus-visible{outline:2px solid var(--accent);outline-offset:2px}input[type=checkbox]{width:18px;height:18px;accent-color:var(--accent);cursor:pointer}select{accent-color:var(--accent);cursor:pointer}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite;display:inline-block}.btn.loading{pointer-events:none;opacity:.8}@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-black:#000;--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--font-weight-medium:500;--font-weight-bold:700;--tracking-wider:.05em;--radius-lg:.5rem;--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-success:#10b981;--color-warning:#f59e0b;--color-danger:#ef4444}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.fixed{position:fixed}.relative{position:relative}.static{position:static}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-4{margin-top:calc(var(--spacing)*4)}.mt-6{margin-top:calc(var(--spacing)*6)}.mr-2{margin-right:calc(var(--spacing)*2)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-6{margin-bottom:calc(var(--spacing)*6)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.inline-block{display:inline-block}.table{display:table}.w-full{width:100%}.max-w-\[150px\]{max-width:150px}.max-w-\[200px\]{max-width:200px}.max-w-\[300px\]{max-width:300px}.max-w-\[800px\]{max-width:800px}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.items-baseline{align-items:baseline}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing)*1)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-6{gap:calc(var(--spacing)*6)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.rounded-lg{border-radius:var(--radius-lg)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-white\/5{border-color:#ffffff0d}@supports (color:color-mix(in lab,red,red)){.border-white\/5{border-color:color-mix(in oklab,var(--color-white)5%,transparent)}}.bg-success{background-color:var(--color-success)}.bg-white\/10{background-color:#ffffff1a}@supports (color:color-mix(in lab,red,red)){.bg-white\/10{background-color:color-mix(in oklab,var(--color-white)10%,transparent)}}.px-4{padding-inline:calc(var(--spacing)*4)}.py-2{padding-block:calc(var(--spacing)*2)}.pt-4{padding-top:calc(var(--spacing)*4)}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.text-black{color:var(--color-black)}.text-danger{color:var(--color-danger)}.text-success{color:var(--color-success)}.text-warning{color:var(--color-warning)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.opacity-30{opacity:.3}.opacity-70{opacity:.7}.opacity-75{opacity:.75}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}@media(hover:hover){.hover\:bg-success\/80:hover{background-color:#10b981cc}@supports (color:color-mix(in lab,red,red)){.hover\:bg-success\/80:hover{background-color:color-mix(in oklab,var(--color-success)80%,transparent)}}.hover\:bg-white\/5:hover{background-color:#ffffff0d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/5:hover{background-color:color-mix(in oklab,var(--color-white)5%,transparent)}}.hover\:bg-white\/20:hover{background-color:#fff3}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/20:hover{background-color:color-mix(in oklab,var(--color-white)20%,transparent)}}}@media(min-width:48rem){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}}body{-webkit-font-smoothing:antialiased;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif}body.dark{--bg-main:#0f172a;--bg-side:#1e293b;--bg-card:#1e293b;--bg-hover:#334155;--text-main:#94a3b8;--text-bright:#f8fafc;--border:#334155}body:not(.dark){--bg-main:#f8fafc;--bg-side:#fff;--bg-card:#fff;--bg-hover:#f1f5f9;--text-main:#475569;--text-bright:#0f172a;--border:#e2e8f0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}
@@ -0,0 +1,516 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>web_plsql Admin Console</title>
7
+ <link rel="icon" type="image/svg+xml" href="/admin/assets/favicon-mQAM4tVu.svg" />
8
+ <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" />
9
+ <script type="module" crossorigin src="/admin/assets/main-0oxRTIkL.js"></script>
10
+ <link rel="stylesheet" crossorigin href="/admin/assets/main-TYgLak6O.css">
11
+ </head>
12
+ <body class="dark">
13
+ <div class="app-container">
14
+ <aside class="sidebar">
15
+ <div class="logo">
16
+ <span class="material-symbols-rounded">database</span>
17
+ <div style="display: flex; flex-direction: column; line-height: 1">
18
+ <span>web_plsql</span>
19
+ <small id="sidebar-version" style="font-size: 0.65rem; opacity: 0.7; margin-top: 2px"></small>
20
+ </div>
21
+ </div>
22
+ <nav>
23
+ <button data-view="overview" class="active">
24
+ <span class="material-symbols-rounded">dashboard</span>
25
+ Overview
26
+ </button>
27
+ <button data-view="trace">
28
+ <span class="material-symbols-rounded">bolt</span>
29
+ Requests
30
+ </button>
31
+ <button data-view="errors">
32
+ <span class="material-symbols-rounded">error</span>
33
+ Errors
34
+ </button>
35
+ <button data-view="access">
36
+ <span class="material-symbols-rounded">list_alt</span>
37
+ Access Log
38
+ </button>
39
+ <button data-view="pools">
40
+ <span class="material-symbols-rounded">database</span>
41
+ Pools
42
+ </button>
43
+ <button data-view="stats">
44
+ <span class="material-symbols-rounded">query_stats</span>
45
+ Stats
46
+ </button>
47
+ <button data-view="config">
48
+ <span class="material-symbols-rounded">settings</span>
49
+ Configuration
50
+ </button>
51
+ <button data-view="system">
52
+ <span class="material-symbols-rounded">terminal</span>
53
+ System
54
+ </button>
55
+ </nav>
56
+ <div class="status-indicator">
57
+ <span id="server-status-dot" class="dot"></span>
58
+ <span id="server-status-text">Checking...</span>
59
+ </div>
60
+ </aside>
61
+ <main class="content">
62
+ <header class="main-header">
63
+ <h1 id="view-title"><span class="material-symbols-rounded">dashboard</span>Overview</h1>
64
+ <div class="header-toolbar">
65
+ <div class="auto-refresh-group">
66
+ <label for="auto-refresh-toggle">Auto-refresh</label>
67
+ <input type="checkbox" id="auto-refresh-toggle" checked />
68
+ <select id="refresh-interval">
69
+ <option value="1000">1s</option>
70
+ <option value="5000">5s</option>
71
+ <option value="10000" selected>10s</option>
72
+ <option value="30000">30s</option>
73
+ <option value="60000">1m</option>
74
+ </select>
75
+ <button
76
+ id="manual-refresh"
77
+ class="icon-btn icon-sm"
78
+ title="Refresh Now"
79
+ style="border: none; background: none; padding: 0; min-width: auto; min-height: auto; margin-left: 4px"
80
+ >
81
+ <span class="material-symbols-rounded" style="font-size: 20px">refresh</span>
82
+ </button>
83
+ </div>
84
+ <button id="theme-toggle-btn" class="icon-btn" title="Toggle Theme">
85
+ <span class="material-symbols-rounded">dark_mode</span>
86
+ </button>
87
+ </div>
88
+ </header>
89
+
90
+ <section id="view-overview" class="view">
91
+ <div class="metrics-grid">
92
+ <div class="card" title="Time since the server started">
93
+ <div class="card-header">
94
+ <span class="material-symbols-rounded">schedule</span>
95
+ <h3 title="Time since the server started">Uptime</h3>
96
+ </div>
97
+ <p id="uptime-val" title="Total uptime duration">0s</p>
98
+ <small id="start-time-val" title="Exact server start time">-</small>
99
+ </div>
100
+ <div class="card" title="Request throughput and response times">
101
+ <div class="card-header">
102
+ <span class="material-symbols-rounded">swap_vert</span>
103
+ <h3 title="Request throughput and response times">Requests</h3>
104
+ </div>
105
+ <div class="flex items-baseline gap-1 mb-2" title="Current and maximum requests per second">
106
+ <span id="req-per-sec" class="text-2xl font-bold text-bright">0.00</span>
107
+ <span class="text-xs text-main font-medium uppercase mr-2">cur /s</span>
108
+ <span class="text-main opacity-30 mr-2">/</span>
109
+ <span id="max-req-per-sec" class="text-2xl font-bold text-bright">0.00</span>
110
+ <span class="text-xs text-main font-medium uppercase">max /s</span>
111
+ </div>
112
+ <div class="flex gap-4">
113
+ <small class="text-main" title="Average response time">Avg: <span id="avg-resp-time" class="font-bold">0ms</span></small>
114
+ <small class="text-main" title="Maximum response time">Max: <span id="max-resp-time" class="font-bold">0ms</span></small>
115
+ </div>
116
+ </div>
117
+ <div class="card" title="Total number of requests that resulted in an error">
118
+ <div class="card-header">
119
+ <span class="material-symbols-rounded">report</span>
120
+ <h3 title="Total number of requests that resulted in an error">Errors</h3>
121
+ </div>
122
+ <p id="err-count" title="Total error count">0</p>
123
+ </div>
124
+ <div class="card" title="Efficiency of the internal cache">
125
+ <div class="card-header">
126
+ <span class="material-symbols-rounded">cached</span>
127
+ <h3 title="Efficiency of the internal cache">Cache Hit Rate</h3>
128
+ </div>
129
+ <p id="cache-hit-rate-val" title="Percentage of requests served from cache">0%</p>
130
+ <small
131
+ ><span id="cache-hits-val" title="Total cache hits">0</span> hits,
132
+ <span id="cache-misses-val" title="Total cache misses">0</span> misses</small
133
+ >
134
+ </div>
135
+ </div>
136
+
137
+ <div class="card" style="grid-column: span 2">
138
+ <div class="card-header">
139
+ <span class="material-symbols-rounded">monitoring</span>
140
+ <h3>TRAFFIC</h3>
141
+ <div class="header-toolbar ml-auto">
142
+ <select
143
+ id="chart-history-points"
144
+ class="btn-sm"
145
+ style="
146
+ background: var(--bg-hover);
147
+ border: 1px solid var(--border);
148
+ border-radius: 4px;
149
+ color: var(--text-main);
150
+ font-size: 0.75rem;
151
+ padding: 2px 4px;
152
+ "
153
+ >
154
+ <option value="60">Last 1 min</option>
155
+ <option value="300">Last 5 min</option>
156
+ <option value="600" selected>Last 10 min</option>
157
+ <option value="1800">Last 30 min</option>
158
+ <option value="3600">Last 1 hour</option>
159
+ <option value="7200">Last 2 hours</option>
160
+ <option value="43200">Last 12 hours</option>
161
+ <option value="86400">Last 24 hours</option>
162
+ </select>
163
+ </div>
164
+ </div>
165
+ <div class="chart-container">
166
+ <canvas id="traffic-chart"></canvas>
167
+ </div>
168
+ </div>
169
+ </section>
170
+
171
+ <section id="view-pools" class="view" style="display: none">
172
+ <div id="pools-container" class="pools-grid"></div>
173
+ <div class="card">
174
+ <div class="card-header">
175
+ <span class="material-symbols-rounded">analytics</span>
176
+ <h3>Pool Usage History</h3>
177
+ </div>
178
+ <div class="chart-container">
179
+ <canvas id="pool-chart"></canvas>
180
+ </div>
181
+ </div>
182
+ </section>
183
+
184
+ <section id="view-errors" class="view" style="display: none">
185
+ <div class="header-toolbar mb-4" style="justify-content: flex-start; gap: 12px">
186
+ <div class="search-group" style="flex: 1; max-width: 400px">
187
+ <span
188
+ class="material-symbols-rounded"
189
+ style="position: absolute; left: 8px; top: 50%; transform: translateY(-50%); font-size: 18px; opacity: 0.5"
190
+ >search</span
191
+ >
192
+ <input
193
+ type="text"
194
+ id="error-filter"
195
+ placeholder="Filter errors (URL, message, method)..."
196
+ class="input-sm"
197
+ style="width: 100%; padding-left: 32px"
198
+ />
199
+ </div>
200
+ <div class="flex items-center gap-2">
201
+ <label for="error-limit" class="text-xs text-main">Max entries:</label>
202
+ <input type="number" id="error-limit" value="100" min="1" max="5000" class="input-sm" style="width: 100px" />
203
+ </div>
204
+ <button id="error-load-btn" class="btn btn-sm btn-primary">
205
+ <span class="material-symbols-rounded" style="font-size: 18px">refresh</span>
206
+ Load Errors
207
+ </button>
208
+ </div>
209
+ <div class="table-container">
210
+ <table id="errors-table">
211
+ <thead></thead>
212
+ <tbody></tbody>
213
+ </table>
214
+ </div>
215
+ </section>
216
+
217
+ <section id="view-trace" class="view" style="display: none">
218
+ <div class="header-toolbar mb-4" style="justify-content: flex-start; gap: 12px">
219
+ <div class="search-group" style="flex: 1; max-width: 300px">
220
+ <span
221
+ class="material-symbols-rounded"
222
+ style="position: absolute; left: 8px; top: 50%; transform: translateY(-50%); font-size: 18px; opacity: 0.5"
223
+ >search</span
224
+ >
225
+ <input type="text" id="trace-filter" placeholder="Filter traces..." class="input-sm" style="width: 100%; padding-left: 32px" />
226
+ </div>
227
+ <div class="flex items-center gap-2">
228
+ <label for="trace-limit" class="text-xs text-main">Max entries:</label>
229
+ <input type="number" id="trace-limit" value="100" min="1" max="5000" class="input-sm" style="width: 80px" />
230
+ </div>
231
+ <button id="trace-load-btn" class="btn btn-sm btn-primary">
232
+ <span class="material-symbols-rounded" style="font-size: 18px">refresh</span>
233
+ Refresh
234
+ </button>
235
+ <button id="trace-clear-btn" class="btn btn-sm btn-danger">
236
+ <span class="material-symbols-rounded" style="font-size: 18px">delete</span>
237
+ Clear
238
+ </button>
239
+ <button
240
+ id="trace-status-toggle"
241
+ 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"
242
+ >
243
+ Tracing: OFF
244
+ </button>
245
+ </div>
246
+ <div class="table-container">
247
+ <table id="trace-table">
248
+ <thead></thead>
249
+ <tbody></tbody>
250
+ </table>
251
+ </div>
252
+ </section>
253
+
254
+ <section id="view-access" class="view" style="display: none">
255
+ <div class="header-toolbar mb-4" style="justify-content: flex-start; gap: 12px">
256
+ <div class="search-group" style="flex: 1; max-width: 400px">
257
+ <span
258
+ class="material-symbols-rounded"
259
+ style="position: absolute; left: 8px; top: 50%; transform: translateY(-50%); font-size: 18px; opacity: 0.5"
260
+ >search</span
261
+ >
262
+ <input type="text" id="access-filter" placeholder="Filter logs..." class="input-sm" style="width: 100%; padding-left: 32px" />
263
+ </div>
264
+ <div class="flex items-center gap-2">
265
+ <label for="access-limit" class="text-xs text-main">Max entries:</label>
266
+ <input type="number" id="access-limit" value="100" min="1" max="5000" class="input-sm" style="width: 100px" />
267
+ </div>
268
+ <button id="access-load-btn" class="btn btn-sm btn-primary">
269
+ <span class="material-symbols-rounded" style="font-size: 18px">refresh</span>
270
+ Load Logs
271
+ </button>
272
+ <small id="access-log-range" class="text-main" style="margin-left: auto">No logs loaded</small>
273
+ </div>
274
+ <div class="terminal-container">
275
+ <pre id="access-log-view" class="terminal" title="Real-time access logs from the server"></pre>
276
+ </div>
277
+ </section>
278
+
279
+ <section id="view-stats" class="view" style="display: none">
280
+ <div class="header-toolbar mb-4" style="justify-content: flex-start; gap: 12px">
281
+ <div class="flex items-center gap-2">
282
+ <label for="stats-limit" class="text-xs text-main">Max entries:</label>
283
+ <input type="number" id="stats-limit" value="50" min="1" max="1000" class="input-sm" style="width: 80px" />
284
+ </div>
285
+ <button id="stats-load-btn" class="btn btn-sm btn-primary">
286
+ <span class="material-symbols-rounded" style="font-size: 18px">refresh</span>
287
+ Load Stats
288
+ </button>
289
+ <small id="stats-history-info" class="text-main" style="margin-left: auto">No stats loaded</small>
290
+ </div>
291
+ <div class="table-container">
292
+ <table id="stats-table">
293
+ <thead>
294
+ <tr>
295
+ <th title="Timestamp of the interval">Timestamp</th>
296
+ <th title="Requests in this interval" class="text-center">Req</th>
297
+ <th title="Errors in this interval" class="text-center">Err</th>
298
+ <th title="Min Latency (ms)" class="text-right">Min</th>
299
+ <th title="Avg Latency (ms)" class="text-right">Avg</th>
300
+ <th title="95th Percentile Latency (ms)" class="text-right">P95</th>
301
+ <th title="99th Percentile Latency (ms)" class="text-right">P99</th>
302
+ <th title="Max Latency (ms)" class="text-right">Max</th>
303
+ <th title="CPU Usage (%)" class="text-right">CPU %</th>
304
+ <th title="Resident Set Size (MB)" class="text-right">RSS</th>
305
+ <th title="Heap Used (MB)" class="text-right">Heap</th>
306
+ </tr>
307
+ </thead>
308
+ <tbody></tbody>
309
+ </table>
310
+ </div>
311
+ </section>
312
+
313
+ <section id="view-config" class="view" style="display: none">
314
+ <div id="config-view"></div>
315
+ </section>
316
+
317
+ <section id="view-system" class="view view-system-compact" style="display: none">
318
+ <div class="metrics-grid mb-4">
319
+ <div class="card">
320
+ <div class="card-header">
321
+ <span class="material-symbols-rounded">info</span>
322
+ <h3>Server Information</h3>
323
+ </div>
324
+ <div class="text-sm text-main">
325
+ <div class="stat-row">
326
+ <span>Middleware Version</span>
327
+ <span id="middleware-version" class="font-mono text-accent font-bold">-</span>
328
+ </div>
329
+ <div class="stat-row">
330
+ <span>Node.js Version</span>
331
+ <span id="node-version" class="font-mono text-accent font-bold">-</span>
332
+ </div>
333
+ <div class="stat-row">
334
+ <span>Platform</span>
335
+ <span id="platform-info" class="text-accent font-bold">-</span>
336
+ </div>
337
+ </div>
338
+ </div>
339
+ <div class="card">
340
+ <div class="card-header">
341
+ <span class="material-symbols-rounded">schedule</span>
342
+ <h3>Runtime</h3>
343
+ </div>
344
+ <div class="text-sm text-main">
345
+ <div class="stat-row">
346
+ <span>Server Uptime</span>
347
+ <span id="system-uptime" class="text-accent font-bold">-</span>
348
+ </div>
349
+ <div class="stat-row">
350
+ <span>Start Time</span>
351
+ <span id="system-start-time" class="text-accent font-bold">-</span>
352
+ </div>
353
+ <div class="stat-row">
354
+ <span>Status</span>
355
+ <span id="system-status" class="status-dot">
356
+ <span class="dot running"></span>
357
+ <span id="system-status-text" class="text-accent font-bold">-</span>
358
+ </span>
359
+ </div>
360
+ </div>
361
+ </div>
362
+ <div class="card">
363
+ <div class="card-header">
364
+ <span class="material-symbols-rounded">insights</span>
365
+ <h3>Activity</h3>
366
+ </div>
367
+ <div class="text-sm text-main">
368
+ <div class="stat-row">
369
+ <span>Total Requests</span>
370
+ <span id="total-requests" class="font-mono text-accent font-bold">-</span>
371
+ </div>
372
+ <div class="stat-row">
373
+ <span>Total Errors</span>
374
+ <span id="total-errors" class="font-mono text-danger font-bold">-</span>
375
+ </div>
376
+ <div class="stat-row">
377
+ <span>Active Pools</span>
378
+ <span id="active-pools" class="font-mono text-accent font-bold">-</span>
379
+ </div>
380
+ </div>
381
+ </div>
382
+ </div>
383
+
384
+ <div class="metrics-grid">
385
+ <div class="card resource-card" title="Memory usage statistics for the Node.js process">
386
+ <div class="card-header">
387
+ <span class="material-symbols-rounded">memory</span>
388
+ <h3 title="Memory usage statistics for the Node.js process">Memory Usage</h3>
389
+ </div>
390
+ <div class="stat-container-wrapper text-sm text-main">
391
+ <div class="stat-container">
392
+ <div class="stat-row">
393
+ <span>Memory Usage (%)</span>
394
+ <span id="memory-percent" class="font-mono text-accent font-bold">-</span>
395
+ </div>
396
+ <div class="stat-row" title="Memory currently used by Node.js objects">
397
+ <span>Heap Used</span>
398
+ <div class="stat-values">
399
+ <span id="memory-heap-used" class="font-mono text-accent font-bold">-</span>
400
+ <small class="min-max">max: <span id="memory-heap-used-max">-</span></small>
401
+ </div>
402
+ </div>
403
+ <div class="stat-row" title="Total memory allocated for the heap">
404
+ <span>Heap Total</span>
405
+ <div class="stat-values">
406
+ <span id="memory-heap-total" class="font-mono text-accent font-bold">-</span>
407
+ <small class="min-max">max: <span id="memory-heap-total-max">-</span></small>
408
+ </div>
409
+ </div>
410
+ <div class="stat-row" title="Resident Set Size - total memory used by the process">
411
+ <span>RSS</span>
412
+ <div class="stat-values">
413
+ <span id="memory-rss" class="font-mono text-accent font-bold">-</span>
414
+ <small class="min-max">max: <span id="memory-rss-max">-</span></small>
415
+ </div>
416
+ </div>
417
+ </div>
418
+ </div>
419
+ <div class="chart-container-mini">
420
+ <canvas id="memory-chart"></canvas>
421
+ </div>
422
+ </div>
423
+ <div class="card resource-card" title="CPU time consumed by the process">
424
+ <div class="card-header">
425
+ <span class="material-symbols-rounded">speed</span>
426
+ <h3 title="CPU time consumed by the process">CPU Usage</h3>
427
+ </div>
428
+ <div class="stat-container-wrapper text-sm text-main">
429
+ <div class="stat-container">
430
+ <div class="stat-row">
431
+ <span>CPU Usage (%)</span>
432
+ <span id="cpu-percent" class="font-mono text-accent font-bold">-</span>
433
+ </div>
434
+ <div class="stat-row" title="Time spent in user code">
435
+ <span>User</span>
436
+ <div class="stat-values">
437
+ <span id="cpu-user" class="font-mono text-accent font-bold">-</span>
438
+ <small class="min-max">max: <span id="cpu-user-max">-</span></small>
439
+ </div>
440
+ </div>
441
+ <div class="stat-row" title="Time spent in system (kernel) code">
442
+ <span>System</span>
443
+ <div class="stat-values">
444
+ <span id="cpu-system" class="font-mono text-accent font-bold">-</span>
445
+ <small class="min-max">max: <span id="cpu-system-max">-</span></small>
446
+ </div>
447
+ </div>
448
+ <div class="stat-row">
449
+ <span>Hardware</span>
450
+ <span id="cpu-cores-info" class="text-accent font-bold">-</span>
451
+ </div>
452
+ </div>
453
+ </div>
454
+ <div class="chart-container-mini">
455
+ <canvas id="cpu-chart"></canvas>
456
+ </div>
457
+ </div>
458
+ </div>
459
+
460
+ <div class="card danger-zone">
461
+ <h3 class="danger-zone-title">Danger Zone</h3>
462
+ <div style="display: flex; gap: 12px; margin-top: 16px">
463
+ <button id="btn-clear-all-cache" class="btn btn-sm btn-warning">Clear All Caches</button>
464
+ <button id="btn-pause" class="btn btn-sm btn-warning">Pause Server</button>
465
+ <button id="btn-resume" class="btn btn-sm btn-success" style="display: none">Resume Server</button>
466
+ <button id="btn-stop" class="btn btn-sm btn-danger">Stop Server</button>
467
+ </div>
468
+ </div>
469
+ </section>
470
+ </main>
471
+ </div>
472
+ <div id="error-modal" class="modal" style="display: none">
473
+ <div class="modal-content">
474
+ <div class="modal-header">
475
+ <h3>Error Details</h3>
476
+ <button class="icon-btn" onclick="document.getElementById('error-modal').style.display = 'none'">
477
+ <span class="material-symbols-rounded">close</span>
478
+ </button>
479
+ </div>
480
+ <div class="modal-body">
481
+ <pre id="error-detail-content" class="terminal" style="max-height: 70vh; overflow: auto"></pre>
482
+ </div>
483
+ </div>
484
+ </div>
485
+
486
+ <div id="trace-modal" class="modal" style="display: none">
487
+ <div class="modal-content">
488
+ <div class="modal-header">
489
+ <h3>Trace Details</h3>
490
+ <button class="icon-btn" onclick="document.getElementById('trace-modal').style.display = 'none'">
491
+ <span class="material-symbols-rounded">close</span>
492
+ </button>
493
+ </div>
494
+ <div class="modal-body">
495
+ <pre id="trace-detail-content" class="terminal" style="max-height: 70vh; overflow: auto"></pre>
496
+ </div>
497
+ </div>
498
+ </div>
499
+
500
+ <div id="offline-modal" class="modal" style="display: none">
501
+ <div class="modal-content" style="max-width: 400px; text-align: center">
502
+ <div class="modal-body" style="display: flex; flex-direction: column; align-items: center; gap: 16px; padding: 32px">
503
+ <span class="material-symbols-rounded" style="font-size: 48px; color: var(--danger)">wifi_off</span>
504
+ <h3 style="margin: 0; font-size: 1.25rem; color: var(--text-bright)">Connection Lost</h3>
505
+ <p style="margin: 0; color: var(--text-main)">The server is unreachable. Please check your connection or server status.</p>
506
+ <p id="offline-countdown" style="margin: 0; color: var(--text-main); font-size: 0.875rem"></p>
507
+ <button id="btn-reconnect" class="btn btn-primary btn-lg w-full justify-center">
508
+ <span id="reconnect-icon" class="material-symbols-rounded">refresh</span>
509
+ <span id="reconnect-spinner" class="material-symbols-rounded animate-spin" style="display: none">sync</span>
510
+ <span id="reconnect-text">Try Reconnect</span>
511
+ </button>
512
+ </div>
513
+ </div>
514
+ </div>
515
+ </body>
516
+ </html>
Binary file
Binary file