nestjs-devtools 1.4.0 → 1.5.1
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.
- package/dist/toolbar/profiler.js +182 -182
- package/dist/toolbar/profiler.js.map +1 -1
- package/dist/toolbar/template.js +58 -85
- package/dist/toolbar/template.js.map +1 -1
- package/package.json +1 -1
package/dist/toolbar/profiler.js
CHANGED
|
@@ -3,25 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.PROFILER_PAGE = void 0;
|
|
4
4
|
const PROFILER_PAGE = (config) => {
|
|
5
5
|
const { theme = 'dark' } = config ?? {};
|
|
6
|
-
const dark = theme === 'dark';
|
|
7
|
-
const bg = dark ? '#0f172a' : '#f8fafc';
|
|
8
|
-
const fg = dark ? '#e2e8f0' : '#1e293b';
|
|
9
|
-
const cardBg = dark ? '#1e293b' : '#ffffff';
|
|
10
|
-
const borderClr = dark ? '#334155' : '#e2e8f0';
|
|
11
|
-
const headerBg = dark ? '#0f172a' : '#ffffff';
|
|
12
|
-
const dimText = dark ? '#64748b' : '#94a3b8';
|
|
13
|
-
const dimmerText = dark ? '#475569' : '#cbd5e1';
|
|
14
|
-
const accentText = dark ? '#38bdf8' : '#0284c7';
|
|
15
|
-
const labelFg = dark ? '#f1f5f9' : '#0f172a';
|
|
16
|
-
const navBg = dark ? '#1e293b' : '#f1f5f9';
|
|
17
|
-
const navFg = dark ? '#94a3b8' : '#475569';
|
|
18
|
-
const I = {
|
|
19
|
-
req: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.5"/><path d="M5 8h6M8 5l3 3-3 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>',
|
|
20
|
-
perf: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.5"/><path d="M8 4v4l2.5 1.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
|
|
21
|
-
db: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><ellipse cx="8" cy="4.5" rx="5" ry="2" stroke="currentColor" stroke-width="1.5"/><path d="M3 4.5v7c0 1.1 2.2 2 5 2s5-.9 5-2v-7" stroke="currentColor" stroke-width="1.5"/><path d="M3 8c0 1.1 2.2 2 5 2s5-.9 5-2" stroke="currentColor" stroke-width="1.5"/></svg>',
|
|
22
|
-
routes: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2 4h12M2 8h12M2 12h12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
|
|
23
|
-
log: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="2" y="2" width="12" height="12" rx="2" stroke="currentColor" stroke-width="1.5"/><path d="M5 6h6M5 9h4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
|
|
24
|
-
};
|
|
25
6
|
return `<!DOCTYPE html>
|
|
26
7
|
<html lang="en">
|
|
27
8
|
<head>
|
|
@@ -30,224 +11,241 @@ const PROFILER_PAGE = (config) => {
|
|
|
30
11
|
<title>NestJS Devtools Profiler</title>
|
|
31
12
|
<style>
|
|
32
13
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
14
|
+
html, body { height: 100%; }
|
|
33
15
|
body {
|
|
34
|
-
font-family:
|
|
35
|
-
background:
|
|
36
|
-
min-height: 100vh;
|
|
16
|
+
font-family: -apple-system,BlinkMacSystemFont,sans-serif;
|
|
17
|
+
background: #f5f5f5; color: #222; font-size: 13px; line-height: 1.5;
|
|
37
18
|
}
|
|
38
|
-
.
|
|
39
|
-
background:
|
|
40
|
-
|
|
41
|
-
position: sticky; top: 0; z-index:
|
|
19
|
+
.toolbar {
|
|
20
|
+
background: #1a1a1a; color: #ccc; display: flex; align-items: center;
|
|
21
|
+
height: 30px; padding: 0 10px; font-size: 11px;
|
|
22
|
+
box-shadow: 0 1px 4px rgba(0,0,0,0.3); position: sticky; top: 0; z-index: 100;
|
|
42
23
|
}
|
|
43
|
-
.
|
|
44
|
-
.
|
|
45
|
-
.
|
|
46
|
-
.nav
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
font-size: 13px; font-weight: 500; transition: all .12s ease;
|
|
24
|
+
.toolbar .brand { font-weight: 700; font-size: 12px; color: #888; padding: 0 12px 0 4px; }
|
|
25
|
+
.toolbar .title { color: #aaa; font-size: 11px; }
|
|
26
|
+
.toolbar .nav { margin-left: auto; display: flex; align-items: center; height: 100%; }
|
|
27
|
+
.toolbar .nav a {
|
|
28
|
+
display: inline-flex; align-items: center; height: 100%; padding: 0 10px;
|
|
29
|
+
color: #888; text-decoration: none; font-size: 11px; cursor: pointer;
|
|
30
|
+
border-left: 1px solid #333; transition: background .1s;
|
|
51
31
|
}
|
|
52
|
-
.
|
|
53
|
-
.nav
|
|
54
|
-
.
|
|
55
|
-
.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
background: ${cardBg}; border-radius: 8px; border: 1px solid ${borderClr};
|
|
59
|
-
overflow: hidden; cursor: pointer; transition: border-color .15s ease;
|
|
32
|
+
.toolbar .nav a:hover { background: #333; color: #ddd; }
|
|
33
|
+
.toolbar .nav a.active { color: #fff; background: #333; }
|
|
34
|
+
.layout { display: flex; min-height: calc(100vh - 30px); }
|
|
35
|
+
.sidebar {
|
|
36
|
+
width: 240px; background: #fff; border-right: 1px solid #ddd;
|
|
37
|
+
padding: 16px; flex-shrink: 0; font-size: 12px;
|
|
60
38
|
}
|
|
61
|
-
.
|
|
62
|
-
.
|
|
63
|
-
|
|
64
|
-
|
|
39
|
+
.sidebar h3 { font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px; color: #999; margin-bottom: 10px; }
|
|
40
|
+
.sidebar .metric { display: flex; justify-content: space-between; padding: 4px 0; font-size: 12px; }
|
|
41
|
+
.sidebar .metric .label { color: #888; }
|
|
42
|
+
.sidebar .metric .value { color: #222; font-weight: 500; text-align: right; }
|
|
43
|
+
.sidebar .section { margin-bottom: 16px; }
|
|
44
|
+
.sidebar .badge { display: inline-block; padding: 1px 6px; border-radius: 3px; font-size: 10px; font-weight: 600; }
|
|
45
|
+
.badge-get { background: #d4edda; color: #155724; }
|
|
46
|
+
.badge-post { background: #cce5ff; color: #004085; }
|
|
47
|
+
.badge-put { background: #fff3cd; color: #856404; }
|
|
48
|
+
.badge-delete { background: #f8d7da; color: #721c24; }
|
|
49
|
+
.badge-patch { background: #e8daef; color: #6c3483; }
|
|
50
|
+
.main { flex: 1; padding: 20px; }
|
|
51
|
+
.panel { background: #fff; border: 1px solid #ddd; margin-bottom: 12px; border-radius: 0; }
|
|
52
|
+
.panel-header {
|
|
53
|
+
padding: 8px 12px; display: flex; align-items: center; gap: 8px;
|
|
54
|
+
cursor: pointer; user-select: none; font-size: 12px; font-weight: 600;
|
|
55
|
+
border-bottom: 1px solid #eee; color: #333;
|
|
65
56
|
}
|
|
66
|
-
.
|
|
67
|
-
.
|
|
68
|
-
.
|
|
69
|
-
.
|
|
70
|
-
.
|
|
71
|
-
.
|
|
72
|
-
.
|
|
73
|
-
.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
.
|
|
78
|
-
.card-body tr:last-child td, .card-body tr:last-child th { border-bottom: none; }
|
|
79
|
-
.badge {
|
|
80
|
-
display: inline-block; padding: 2px 7px; border-radius: 4px;
|
|
81
|
-
font-size: 10px; font-weight: 600; letter-spacing: 0.2px;
|
|
82
|
-
}
|
|
83
|
-
.badge-get { background: #065f4630; color: #34d399; }
|
|
84
|
-
.badge-post { background: #1e3a5f30; color: #93c5fd; }
|
|
85
|
-
.badge-put { background: #713f1230; color: #fcd34d; }
|
|
86
|
-
.badge-delete { background: #7f1d1d30; color: #fca5a5; }
|
|
87
|
-
.badge-patch { background: #581c8730; color: #d8b4fe; }
|
|
88
|
-
.badge-request { background: #0c4a6e30; color: #7dd3fc; }
|
|
89
|
-
.empty { padding: 20px; text-align: center; color: ${dimmerText}; font-size: 13px; }
|
|
90
|
-
.mono { font-family: ui-monospace,SF Mono,Menlo,monospace; font-size: 11px; }
|
|
91
|
-
.history-wrap { background: ${cardBg}; border: 1px solid ${borderClr}; border-radius: 8px; overflow: hidden; }
|
|
92
|
-
.history-table { width: 100%; border-collapse: collapse; font-size: 12px; }
|
|
93
|
-
.history-table th { padding: 10px 14px; text-align: left; color: ${dimText}; font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.3px; border-bottom: 1px solid ${borderClr}; background: ${dark ? '#0f172a' : '#f8fafc'}; }
|
|
94
|
-
.history-table td { padding: 10px 14px; border-bottom: 1px solid ${borderClr}; }
|
|
95
|
-
.history-table tr:last-child td { border-bottom: none; }
|
|
96
|
-
.history-table tr:hover td { background: ${dark ? '#33415520' : '#f1f5f9'}; }
|
|
97
|
-
.error-text { color: #f87171; font-weight: 600; }
|
|
98
|
-
.warn-text { color: #fbbf24; font-weight: 600; }
|
|
99
|
-
.ok-text { color: #34d399; font-weight: 600; }
|
|
100
|
-
.qlabel { display: inline-block; width: 18px; height: 18px; line-height: 18px; text-align: center; border-radius: 3px; font-size: 10px; font-weight: 700; margin-right: 6px; color: #fff; flex-shrink: 0; }
|
|
101
|
-
.qlabel-1 { background: #3b82f6; }
|
|
102
|
-
.qlabel-2 { background: #8b5cf6; }
|
|
103
|
-
.qlabel-3 { background: #10b981; }
|
|
104
|
-
.query-row { display: flex; align-items: flex-start; padding: 6px 0; gap: 6px; border-bottom: 1px solid ${borderClr}; }
|
|
57
|
+
.panel-header:hover { background: #fafafa; }
|
|
58
|
+
.panel-header .summary { color: #999; font-weight: 400; font-size: 11px; margin-left: auto; }
|
|
59
|
+
.panel-body { display: none; padding: 10px 12px 12px; font-size: 12px; }
|
|
60
|
+
.panel-body.open { display: block; }
|
|
61
|
+
.panel-body table { width: 100%; border-collapse: collapse; }
|
|
62
|
+
.panel-body td, .panel-body th { padding: 4px 8px; text-align: left; vertical-align: top; border-bottom: 1px solid #eee; font-size: 12px; }
|
|
63
|
+
.panel-body th { color: #888; font-weight: 500; width: 100px; }
|
|
64
|
+
.panel-body tr:last-child td, .panel-body tr:last-child th { border-bottom: none; }
|
|
65
|
+
.empty { color: #bbb; font-size: 12px; }
|
|
66
|
+
.mono { font-family: SF Mono,Menlo,monospace; font-size: 11px; }
|
|
67
|
+
.query-table { width: 100%; }
|
|
68
|
+
.query-row { display: flex; align-items: flex-start; padding: 5px 0; gap: 6px; border-bottom: 1px solid #eee; font-size: 11px; }
|
|
105
69
|
.query-row:last-child { border-bottom: none; }
|
|
106
|
-
.query-
|
|
107
|
-
.query-
|
|
108
|
-
.
|
|
70
|
+
.query-num { color: #999; width: 22px; flex-shrink: 0; }
|
|
71
|
+
.query-sql { font-family: SF Mono,Menlo,monospace; word-break: break-all; flex: 1; }
|
|
72
|
+
.query-time { color: #b8860b; white-space: nowrap; font-family: SF Mono,Menlo,monospace; flex-shrink: 0; }
|
|
73
|
+
.log-row { display: flex; align-items: flex-start; gap: 8px; padding: 3px 0; border-bottom: 1px solid #eee; font-size: 11px; }
|
|
109
74
|
.log-row:last-child { border-bottom: none; }
|
|
110
|
-
.log-level {
|
|
111
|
-
.
|
|
112
|
-
.
|
|
113
|
-
.
|
|
114
|
-
.route-
|
|
115
|
-
.
|
|
116
|
-
.
|
|
117
|
-
.
|
|
118
|
-
.
|
|
119
|
-
.
|
|
120
|
-
.
|
|
75
|
+
.log-level { width: 44px; font-weight: 600; font-size: 10px; text-transform: uppercase; flex-shrink: 0; }
|
|
76
|
+
.log-error { color: #e74c3c; }
|
|
77
|
+
.log-warn { color: #f39c12; }
|
|
78
|
+
.log-info { color: #888; }
|
|
79
|
+
.route-group { padding: 4px 0; }
|
|
80
|
+
.route-group-header { font-weight: 600; font-size: 11px; color: #2e8b57; padding: 3px 0; }
|
|
81
|
+
.route-item { padding: 1px 0 1px 14px; font-family: SF Mono,Menlo,monospace; font-size: 11px; }
|
|
82
|
+
.route-controller { color: #999; }
|
|
83
|
+
.exception-box { background: #fdf0ef; border-radius: 3px; padding: 8px; }
|
|
84
|
+
.exception-box .msg { color: #e74c3c; font-weight: 600; font-size: 12px; margin-bottom: 4px; }
|
|
85
|
+
.exception-box .stack { font-family: SF Mono,Menlo,monospace; font-size: 11px; color: #888; white-space: pre-wrap; line-height: 1.4; }
|
|
86
|
+
.field-row { display: flex; padding: 3px 0; font-size: 11px; }
|
|
87
|
+
.field-label { color: #888; width: 90px; flex-shrink: 0; }
|
|
88
|
+
.field-value { word-break: break-all; }
|
|
89
|
+
.error-text { color: #e74c3c; font-weight: 600; }
|
|
90
|
+
.warn-text { color: #f39c12; font-weight: 600; }
|
|
91
|
+
.ok-text { color: #27ae60; font-weight: 600; }
|
|
92
|
+
.status-badge { display: inline-block; padding: 1px 6px; border-radius: 2px; font-size: 11px; font-weight: 600; }
|
|
93
|
+
.status-200 { background: #d4edda; color: #155724; }
|
|
94
|
+
.status-300 { background: #fff3cd; color: #856404; }
|
|
95
|
+
.status-400 { background: #f8d7da; color: #721c24; }
|
|
96
|
+
.status-500 { background: #f8d7da; color: #721c24; }
|
|
121
97
|
</style>
|
|
122
98
|
</head>
|
|
123
99
|
<body>
|
|
124
|
-
<div class="
|
|
125
|
-
<
|
|
126
|
-
<span>NestJS Devtools Profiler</span>
|
|
127
|
-
</div>
|
|
128
|
-
<div class="container">
|
|
100
|
+
<div class="toolbar">
|
|
101
|
+
<span class="brand">ND</span>
|
|
102
|
+
<span class="title">NestJS Devtools Profiler</span>
|
|
129
103
|
<div class="nav">
|
|
130
|
-
<
|
|
131
|
-
<
|
|
104
|
+
<a class="active" data-tab="dashboard">Dashboard</a>
|
|
105
|
+
<a data-tab="history">History</a>
|
|
132
106
|
</div>
|
|
133
|
-
|
|
134
|
-
|
|
107
|
+
</div>
|
|
108
|
+
<div class="layout">
|
|
109
|
+
<div class="sidebar" id="sidebar">
|
|
110
|
+
<div class="section">
|
|
111
|
+
<h3>Request</h3>
|
|
112
|
+
<div id="sidebar-metrics"></div>
|
|
113
|
+
</div>
|
|
135
114
|
</div>
|
|
136
|
-
<div
|
|
137
|
-
<div class="
|
|
138
|
-
<
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
115
|
+
<div class="main">
|
|
116
|
+
<div id="tab-dashboard" class="tab-content">
|
|
117
|
+
<div id="panel-list"></div>
|
|
118
|
+
</div>
|
|
119
|
+
<div id="tab-history" class="tab-content" style="display:none">
|
|
120
|
+
<div class="panel">
|
|
121
|
+
<table style="width:100%;border-collapse:collapse;font-size:12px">
|
|
122
|
+
<thead><tr style="background:#fafafa"><th style="padding:8px 12px;text-align:left;color:#888;font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:0.5px;border-bottom:1px solid #ddd">Time</th><th style="padding:8px 12px;text-align:left;color:#888;font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:0.5px;border-bottom:1px solid #ddd">Method</th><th style="padding:8px 12px;text-align:left;color:#888;font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:0.5px;border-bottom:1px solid #ddd">Path</th><th style="padding:8px 12px;text-align:left;color:#888;font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:0.5px;border-bottom:1px solid #ddd">Status</th><th style="padding:8px 12px;text-align:left;color:#888;font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:0.5px;border-bottom:1px solid #ddd">Duration</th></tr></thead>
|
|
123
|
+
<tbody id="history-body"></tbody>
|
|
124
|
+
</table>
|
|
125
|
+
</div>
|
|
142
126
|
</div>
|
|
143
127
|
</div>
|
|
144
128
|
</div>
|
|
145
129
|
<script>
|
|
146
|
-
(function()
|
|
130
|
+
(function(){
|
|
147
131
|
var BASE = window.location.pathname.replace(/\\/__devtools\\/?$/, '');
|
|
148
|
-
var
|
|
132
|
+
var activeTab = 'dashboard';
|
|
133
|
+
var panelData = {};
|
|
149
134
|
|
|
150
135
|
function escape(s) { return s==null?'':String(s).replace(/[&<>"]/g,function(m){return {'&':'&','<':'<','>':'>','"':'"'}[m]}); }
|
|
151
136
|
|
|
152
|
-
document.querySelectorAll('[data-tab]').forEach(function(
|
|
153
|
-
|
|
137
|
+
document.querySelectorAll('[data-tab]').forEach(function(el){
|
|
138
|
+
el.addEventListener('click', function(){
|
|
154
139
|
document.querySelectorAll('[data-tab]').forEach(function(b){b.classList.remove('active')});
|
|
155
|
-
document.querySelectorAll('.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
140
|
+
document.querySelectorAll('.tab-content').forEach(function(c){c.style.display='none'});
|
|
141
|
+
el.classList.add('active');
|
|
142
|
+
activeTab = el.getAttribute('data-tab');
|
|
143
|
+
document.getElementById('tab-'+activeTab).style.display='';
|
|
144
|
+
if (activeTab==='history') loadHistory();
|
|
159
145
|
});
|
|
160
146
|
});
|
|
161
147
|
|
|
162
|
-
function
|
|
148
|
+
function renderPanelContent(detail) {
|
|
163
149
|
if (!detail || !detail.details) return '<div class="empty">No data</div>';
|
|
164
150
|
var d = detail.details;
|
|
165
151
|
var h = '<table>';
|
|
166
152
|
for (var k in d) {
|
|
167
153
|
var v = d[k];
|
|
168
|
-
if (k
|
|
169
|
-
if (v.length
|
|
170
|
-
h
|
|
154
|
+
if (k==='queries' && Array.isArray(v)) {
|
|
155
|
+
if (v.length===0) { h+='<tr><td colspan="2" style="padding:6px 0"><span class="empty">No queries</span></td></tr>'; continue; }
|
|
156
|
+
h+='<tr><th>Queries</th><td>';
|
|
171
157
|
v.forEach(function(q,i){
|
|
172
|
-
|
|
173
|
-
h += '<div class="query-row"><span class="qlabel '+cls+'">'+(i+1)+'</span><span class="query-sql mono">'+escape(q.sql||'')+'</span><span class="query-time">'+escape(q.duration||'')+'</span></div>';
|
|
158
|
+
h+='<div class="query-row"><span class="query-num">'+(i+1)+'</span><span class="query-sql">'+escape(q.sql||'')+'</span><span class="query-time">'+escape(q.duration||'')+'</span></div>';
|
|
174
159
|
});
|
|
175
|
-
h
|
|
160
|
+
h+='</td></tr>';
|
|
176
161
|
continue;
|
|
177
162
|
}
|
|
178
|
-
if (k
|
|
179
|
-
if (v.length
|
|
180
|
-
h
|
|
163
|
+
if (k==='entries' && Array.isArray(v)) {
|
|
164
|
+
if (v.length===0) { h+='<tr><td colspan="2" style="padding:6px 0"><span class="empty">No entries</span></td></tr>'; continue; }
|
|
165
|
+
h+='<tr><th>Logs</th><td>';
|
|
181
166
|
v.forEach(function(e){
|
|
182
|
-
var lc = e.level==='error' ? 'error
|
|
183
|
-
h
|
|
167
|
+
var lc = e.level==='error' ? 'log-error' : e.level==='warn' ? 'log-warn' : 'log-info';
|
|
168
|
+
h+='<div class="log-row"><span class="log-level '+lc+'">'+escape(e.level||'')+'</span><span>'+escape(e.message||'')+'</span></div>';
|
|
184
169
|
});
|
|
185
|
-
h
|
|
170
|
+
h+='</td></tr>';
|
|
186
171
|
continue;
|
|
187
172
|
}
|
|
188
|
-
if (k
|
|
189
|
-
if (v.length
|
|
190
|
-
h
|
|
173
|
+
if (k==='grouped' && Array.isArray(v)) {
|
|
174
|
+
if (v.length===0) { h+='<tr><td colspan="2" style="padding:6px 0"><span class="empty">No routes</span></td></tr>'; continue; }
|
|
175
|
+
h+='<tr><th>Routes</th><td>';
|
|
191
176
|
v.forEach(function(g){
|
|
192
|
-
h
|
|
177
|
+
h+='<div class="route-group"><div class="route-group-header">'+escape(g.method||'')+' <span style="color:#999;font-weight:400">('+(g.count||0)+')</span></div>';
|
|
193
178
|
if (g.routes) g.routes.forEach(function(r){
|
|
194
|
-
h
|
|
179
|
+
h+='<div class="route-item">'+escape(r.path||'')+' <span class="route-controller">('+escape(r.controller||'')+')</span></div>';
|
|
195
180
|
});
|
|
196
|
-
h
|
|
181
|
+
h+='</div>';
|
|
197
182
|
});
|
|
198
|
-
h
|
|
183
|
+
h+='</td></tr>';
|
|
199
184
|
continue;
|
|
200
185
|
}
|
|
201
|
-
if (k
|
|
202
|
-
h
|
|
186
|
+
if (k==='exception' && v && typeof v==='object') {
|
|
187
|
+
h+='<tr><td colspan="2"><div class="exception-box"><div class="msg">'+escape(v.message||'')+'</div><div class="stack">'+escape(v.stack||'')+'</div></div></td></tr>';
|
|
203
188
|
continue;
|
|
204
189
|
}
|
|
205
|
-
if (k
|
|
206
|
-
h
|
|
190
|
+
if (k==='stack') continue;
|
|
191
|
+
h+='<tr><th>'+escape(k)+'</th><td class="mono">'+escape(typeof v==='object'?JSON.stringify(v):v)+'</td></tr>';
|
|
207
192
|
}
|
|
208
|
-
h
|
|
193
|
+
h+='</table>';
|
|
209
194
|
return h;
|
|
210
195
|
}
|
|
211
196
|
|
|
212
197
|
function loadDashboard() {
|
|
213
198
|
fetch(BASE + '/__devtools/data').then(function(r){return r.json()}).then(function(d){
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
var
|
|
199
|
+
panelData = d;
|
|
200
|
+
var list = document.getElementById('panel-list');
|
|
201
|
+
var sidebar = document.getElementById('sidebar-metrics');
|
|
202
|
+
list.innerHTML = '';
|
|
203
|
+
sidebar.innerHTML = '';
|
|
217
204
|
var order = ['request','performance','database','routes','logs'];
|
|
205
|
+
var firstReq = null;
|
|
218
206
|
order.forEach(function(key){
|
|
219
207
|
var p = d[key];
|
|
220
208
|
if (!p || !p.label) return;
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
'<div class="
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
var body = card.querySelector('.card-body');
|
|
209
|
+
if (!firstReq) firstReq = p;
|
|
210
|
+
var panel = document.createElement('div');
|
|
211
|
+
panel.className = 'panel';
|
|
212
|
+
panel.innerHTML =
|
|
213
|
+
'<div class="panel-header"><span>'+escape(p.label)+'</span><span class="summary">'+escape(p.summary||'')+'</span></div>'+
|
|
214
|
+
'<div class="panel-body">'+renderPanelContent(p)+'</div>';
|
|
215
|
+
panel.querySelector('.panel-header').addEventListener('click', function(){
|
|
216
|
+
var body = this.nextElementSibling;
|
|
230
217
|
body.classList.toggle('open');
|
|
231
218
|
});
|
|
232
|
-
|
|
219
|
+
list.appendChild(panel);
|
|
233
220
|
});
|
|
234
221
|
for (var key in d) {
|
|
235
|
-
if (order.indexOf(key)
|
|
222
|
+
if (order.indexOf(key)!==-1) continue;
|
|
236
223
|
var p = d[key];
|
|
237
224
|
if (!p || !p.label) continue;
|
|
238
|
-
var
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
'<div class="
|
|
242
|
-
'<div class="
|
|
243
|
-
|
|
244
|
-
var body =
|
|
225
|
+
var panel = document.createElement('div');
|
|
226
|
+
panel.className = 'panel';
|
|
227
|
+
panel.innerHTML =
|
|
228
|
+
'<div class="panel-header"><span>'+escape(p.label)+'</span><span class="summary">'+escape(p.summary||'')+'</span></div>'+
|
|
229
|
+
'<div class="panel-body">'+renderPanelContent(p)+'</div>';
|
|
230
|
+
panel.querySelector('.panel-header').addEventListener('click', function(){
|
|
231
|
+
var body = this.nextElementSibling;
|
|
245
232
|
body.classList.toggle('open');
|
|
246
233
|
});
|
|
247
|
-
|
|
234
|
+
list.appendChild(panel);
|
|
235
|
+
}
|
|
236
|
+
if (firstReq && firstReq.details) {
|
|
237
|
+
var dd = firstReq.details;
|
|
238
|
+
sidebar.innerHTML =
|
|
239
|
+
'<div class="metric"><span class="label">Method</span><span class="value"><span class="badge badge-'+((dd.method||'get').toLowerCase())+'">'+escape(dd.method||'')+'</span></span></div>'+
|
|
240
|
+
'<div class="metric"><span class="label">Path</span><span class="value mono">'+escape(dd.path||'')+'</span></div>'+
|
|
241
|
+
'<div class="metric"><span class="label">Status</span><span class="value"><span class="status-badge status-'+(dd.status||'')+'">'+escape(dd.status||'')+'</span></span></div>'+
|
|
242
|
+
'<div class="metric"><span class="label">Duration</span><span class="value">'+escape(dd.duration||'')+'</span></div>'+
|
|
243
|
+
'<div class="metric"><span class="label">Memory</span><span class="value">'+escape(dd.memory||'')+'</span></div>'+
|
|
244
|
+
'<div class="metric"><span class="label">Route</span><span class="value mono" style="font-size:10px">'+escape(dd.route||'')+'</span></div>';
|
|
248
245
|
}
|
|
249
|
-
}).catch(function(){
|
|
250
|
-
|
|
246
|
+
}).catch(function(e){
|
|
247
|
+
console.error('[Devtools] Failed to load profiler data:', e);
|
|
248
|
+
document.getElementById('panel-list').innerHTML = '<div class="panel"><div class="panel-body open" style="display:block"><span class="empty">Failed to load profiler data.</span></div></div>';
|
|
251
249
|
});
|
|
252
250
|
}
|
|
253
251
|
|
|
@@ -255,23 +253,25 @@ const PROFILER_PAGE = (config) => {
|
|
|
255
253
|
fetch(BASE + '/__devtools/history').then(function(r){return r.json()}).then(function(rows){
|
|
256
254
|
var tbody = document.getElementById('history-body');
|
|
257
255
|
tbody.innerHTML = '';
|
|
258
|
-
if (!rows || rows.length
|
|
259
|
-
tbody.innerHTML = '<tr><td colspan="5"
|
|
256
|
+
if (!rows || rows.length===0) {
|
|
257
|
+
tbody.innerHTML = '<tr><td colspan="5" style="padding:20px;text-align:center;color:#bbb">No requests recorded yet</td></tr>';
|
|
260
258
|
return;
|
|
261
259
|
}
|
|
262
260
|
rows.forEach(function(r){
|
|
263
|
-
var
|
|
264
|
-
var
|
|
261
|
+
var sc = r.statusCode;
|
|
262
|
+
var scCls = sc>=400 ? 'error-text' : sc>=300 ? 'warn-text' : 'ok-text';
|
|
263
|
+
var mCls = 'badge-'+r.method.toLowerCase();
|
|
265
264
|
tbody.innerHTML += '<tr>'+
|
|
266
|
-
'<td style="color
|
|
267
|
-
'<td><span class="badge '+
|
|
268
|
-
'<td
|
|
269
|
-
'<td><span class="'+
|
|
270
|
-
'<td
|
|
265
|
+
'<td style="padding:8px 12px;border-bottom:1px solid #eee;color:#888">'+escape(new Date(r.timestamp).toLocaleTimeString())+'</td>'+
|
|
266
|
+
'<td style="padding:8px 12px;border-bottom:1px solid #eee"><span class="badge '+mCls+'">'+escape(r.method)+'</span></td>'+
|
|
267
|
+
'<td style="padding:8px 12px;border-bottom:1px solid #eee;font-family:SF Mono,Menlo,monospace;font-size:11px">'+escape(r.path)+'</td>'+
|
|
268
|
+
'<td style="padding:8px 12px;border-bottom:1px solid #eee"><span class="'+scCls+'">'+sc+'</span></td>'+
|
|
269
|
+
'<td style="padding:8px 12px;border-bottom:1px solid #eee;color:#888;font-family:SF Mono,Menlo,monospace">'+(r.duration!=null?r.duration.toFixed(1):'')+' ms</td>'+
|
|
271
270
|
'</tr>';
|
|
272
271
|
});
|
|
273
|
-
}).catch(function(){
|
|
274
|
-
|
|
272
|
+
}).catch(function(e){
|
|
273
|
+
console.error('[Devtools] Failed to load history:', e);
|
|
274
|
+
document.getElementById('history-body').innerHTML = '<tr><td colspan="5" style="padding:20px;text-align:center;color:#bbb">Failed to load history</td></tr>';
|
|
275
275
|
});
|
|
276
276
|
}
|
|
277
277
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profiler.js","sourceRoot":"","sources":["../../toolbar/profiler.ts"],"names":[],"mappings":";;;AAIO,MAAM,aAAa,GAAG,CAAC,MAAoC,EAAE,EAAE;IACpE,MAAM,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"profiler.js","sourceRoot":"","sources":["../../toolbar/profiler.ts"],"names":[],"mappings":";;;AAIO,MAAM,aAAa,GAAG,CAAC,MAAoC,EAAE,EAAE;IACpE,MAAM,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;IAExC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAoRD,CAAC;AACT,CAAC,CAAC;AAxRW,QAAA,aAAa,iBAwRxB"}
|
package/dist/toolbar/template.js
CHANGED
|
@@ -1,50 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TOOLBAR_TEMPLATE = void 0;
|
|
4
|
-
const I = {
|
|
5
|
-
req: '<svg width="12" height="12" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.5"/><path d="M5 8h6M8 5l3 3-3 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>',
|
|
6
|
-
perf: '<svg width="12" height="12" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.5"/><path d="M8 4v4l2.5 1.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
|
|
7
|
-
db: '<svg width="12" height="12" viewBox="0 0 16 16" fill="none"><ellipse cx="8" cy="4.5" rx="5" ry="2" stroke="currentColor" stroke-width="1.5"/><path d="M3 4.5v7c0 1.1 2.2 2 5 2s5-.9 5-2v-7" stroke="currentColor" stroke-width="1.5"/><path d="M3 8c0 1.1 2.2 2 5 2s5-.9 5-2" stroke="currentColor" stroke-width="1.5"/></svg>',
|
|
8
|
-
routes: '<svg width="12" height="12" viewBox="0 0 16 16" fill="none"><path d="M2 4h12M2 8h12M2 12h12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
|
|
9
|
-
log: '<svg width="12" height="12" viewBox="0 0 16 16" fill="none"><rect x="2" y="2" width="12" height="12" rx="2" stroke="currentColor" stroke-width="1.5"/><path d="M5 6h6M5 9h4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
|
|
10
|
-
close: '<svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>',
|
|
11
|
-
profiler: '<svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M2 3h12M2 8h12M2 13h8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="12" r="2.5" stroke="currentColor" stroke-width="1.5"/></svg>',
|
|
12
|
-
chevron: '<svg width="12" height="12" viewBox="0 0 16 16" fill="none"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>',
|
|
13
|
-
};
|
|
14
4
|
const TOOLBAR_TEMPLATE = (config) => {
|
|
15
5
|
const { position = 'bottom-left', theme = 'dark' } = config ?? {};
|
|
16
6
|
const id = '__nestDevtools';
|
|
17
7
|
const uid = Math.random().toString(36).slice(2, 8);
|
|
18
8
|
const isTop = position.startsWith('top');
|
|
19
|
-
const isRight = position.endsWith('right');
|
|
20
9
|
const outerPos = isTop ? 'top:0' : 'bottom:0';
|
|
21
|
-
const outerSide = isRight ? 'right:0' : 'left:0';
|
|
22
|
-
const outerBorder = isTop ? 'border-bottom:1px solid' : 'border-top:1px solid';
|
|
23
10
|
const outerShadow = isTop
|
|
24
|
-
? 'box-shadow:0
|
|
25
|
-
: 'box-shadow:0 -
|
|
26
|
-
const dark = theme === 'dark';
|
|
27
|
-
const bg = dark ? '#0f172a' : '#fafbfc';
|
|
28
|
-
const fg = dark ? '#e2e8f0' : '#1e293b';
|
|
29
|
-
const accent = dark ? '#38bdf8' : '#0284c7';
|
|
30
|
-
const accentBg = dark ? '#0c4a6e30' : '#e0f2fe';
|
|
31
|
-
const panelBg = dark ? '#1e293b' : '#ffffff';
|
|
32
|
-
const borderClr = dark ? '#1e293b' : '#e2e8f0';
|
|
33
|
-
const panelBorder = dark ? '#334155' : '#e2e8f0';
|
|
34
|
-
const btnFg = dark ? '#94a3b8' : '#475569';
|
|
35
|
-
const btnBg = dark ? '#1e293b' : '#f1f5f9';
|
|
36
|
-
const btnHover = dark ? '#334155' : '#e2e8f0';
|
|
37
|
-
const dimText = dark ? '#64748b' : '#94a3b8';
|
|
38
|
-
const labelFg = dark ? '#f1f5f9' : '#0f172a';
|
|
39
|
-
const warnClr = '#f59e0b';
|
|
40
|
-
const errClr = '#ef4444';
|
|
41
|
-
const sqlTimeClr = dark ? '#fbbf24' : '#b45309';
|
|
11
|
+
? 'box-shadow:0 2px 14px rgba(0,0,0,0.5)'
|
|
12
|
+
: 'box-shadow:0 -2px 14px rgba(0,0,0,0.5)';
|
|
42
13
|
return `<script id="${id}">
|
|
43
14
|
(function(){
|
|
44
15
|
var D=document, B=D.body, C='__nestDt'+'${uid}';
|
|
45
16
|
var p = window.location.pathname.replace(\/[^\/]*$/,'') + '/__devtools';
|
|
46
17
|
var c=D.createElement('div'); c.id=C;
|
|
47
|
-
c.innerHTML='<div style="position:fixed;${outerPos}
|
|
18
|
+
c.innerHTML='<div style="position:fixed;${outerPos};left:0;right:0;z-index:99999;font-family:-apple-system,BlinkMacSystemFont,sans-serif;font-size:11px;background:#1a1a1a;color:#ccc;${outerShadow}"><div style="display:flex;align-items:center;height:26px;padding:0 6px;overflow-x:auto;white-space:nowrap;scrollbar-width:none"><span style="font-weight:700;font-size:12px;color:#888;padding:0 10px 0 4px;letter-spacing:0;flex-shrink:0">ND</span><div id="'+C+'-bar" style="display:flex;align-items:center;flex:1;height:100%"></div><a href="'+p+'" target="_blank" style="display:inline-flex;align-items:center;gap:4px;color:#666;text-decoration:none;padding:0 8px;font-size:11px;height:100%;flex-shrink:0" title="Open profiler"><svg width="11" height="11" viewBox="0 0 16 16" fill="none"><path d="M2 4h12M2 8h12M2 12h12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg></a><span id="'+C+'-toggle" style="display:inline-flex;align-items:center;justify-content:center;color:#666;cursor:pointer;padding:0 6px;font-size:13px;height:100%;flex-shrink:0">\u2039</span></div><div id="'+C+'-panel" style="display:none;background:#2b2b2b;font-size:12px;line-height:1.5;color:#ccc;max-height:420px;overflow:hidden"></div></div>';
|
|
48
19
|
B.appendChild(c);
|
|
49
20
|
|
|
50
21
|
var lastActive=null;
|
|
@@ -52,57 +23,62 @@ const TOOLBAR_TEMPLATE = (config) => {
|
|
|
52
23
|
var pnl=D.getElementById(C+'-panel');
|
|
53
24
|
if (lastActive===name) { pnl.style.display='none'; lastActive=null; return; }
|
|
54
25
|
lastActive=name;
|
|
55
|
-
var h='<div style="display:flex;align-items:center;gap:
|
|
56
|
-
h+='<span style="font-weight:600;font-size:13px;color
|
|
57
|
-
h+='<span style="color
|
|
58
|
-
h+='<span style="margin-left:auto;cursor:pointer;color
|
|
26
|
+
var h='<div style="display:flex;align-items:center;gap:10px;padding:9px 14px;border-bottom:1px solid #333">';
|
|
27
|
+
h+='<span style="font-weight:600;font-size:13px;color:#eee">'+escapeHtml(detail.label)+'</span>';
|
|
28
|
+
h+='<span style="color:#888;font-size:11px">'+escapeHtml(detail.summary)+'</span>';
|
|
29
|
+
h+='<span style="margin-left:auto;cursor:pointer;color:#666;padding:2px;font-size:15px" onclick="document.getElementById('+C+'-panel).style.display=\\'none\\';lastActive=null">\u00d7</span>';
|
|
59
30
|
h+='</div>';
|
|
60
|
-
h+='<div style="padding:
|
|
61
|
-
|
|
31
|
+
h+='<div style="padding:10px 14px 14px;overflow-y:auto;max-height:360px">';
|
|
32
|
+
var fields=[];
|
|
62
33
|
for (var k in detail.details) {
|
|
63
34
|
var v=detail.details[k];
|
|
64
|
-
if (k==='queries' && Array.isArray(v)) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
35
|
+
if (k==='queries' && Array.isArray(v)) { fields.push({type:'queries',data:v}); continue; }
|
|
36
|
+
if (k==='entries' && Array.isArray(v)) { fields.push({type:'log',data:v}); continue; }
|
|
37
|
+
if (k==='grouped' && Array.isArray(v)) { fields.push({type:'routes',data:v}); continue; }
|
|
38
|
+
if (k==='exception' && v && typeof v==='object') { fields.push({type:'exception',data:v}); continue; }
|
|
39
|
+
if (k==='stack') continue;
|
|
40
|
+
fields.push({type:'pair',key:k,val:v});
|
|
41
|
+
}
|
|
42
|
+
for (var fi=0;fi<fields.length;fi++) {
|
|
43
|
+
var f=fields[fi];
|
|
44
|
+
if (f.type==='queries') {
|
|
45
|
+
if (f.data.length===0) { h+='<div style="padding:6px 0;color:#666">No queries</div>'; continue; }
|
|
46
|
+
for (var qi=0;qi<f.data.length;qi++) {
|
|
47
|
+
h+='<div style="display:flex;align-items:flex-start;gap:6px;padding:5px 0;border-bottom:1px solid #333;font-size:11px"><span style="color:#666;width:22px;flex-shrink:0">'+(qi+1)+'</span><span style="font-family:SF Mono,Menlo,monospace;word-break:break-all;flex:1">'+escapeHtml(f.data[qi].sql||'')+'</span><span style="color:#dfb840;white-space:nowrap;flex-shrink:0;font-family:SF Mono,Menlo,monospace">'+escapeHtml(f.data[qi].duration||'')+'</span></div>';
|
|
68
48
|
}
|
|
69
49
|
continue;
|
|
70
50
|
}
|
|
71
|
-
if (
|
|
72
|
-
if (
|
|
73
|
-
for (var
|
|
74
|
-
var e=
|
|
75
|
-
var lc=e.level==='error'?'
|
|
76
|
-
|
|
77
|
-
h+='<tr style="background:'+bgc+'"><td style="padding:5px 8px;color:'+lc+';width:52px;font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:0.3px">'+escapeHtml(e.level||'')+'</td><td style="padding:5px 8px;word-break:break-all;color:${labelFg}">'+escapeHtml(e.message||'')+'</td></tr>';
|
|
51
|
+
if (f.type==='log') {
|
|
52
|
+
if (f.data.length===0) { h+='<div style="padding:6px 0;color:#666">No entries</div>'; continue; }
|
|
53
|
+
for (var li=0;li<f.data.length;li++) {
|
|
54
|
+
var e=f.data[li];
|
|
55
|
+
var lc=e.level==='error'?'#e74c3c':e.level==='warn'?'#f39c12':'#888';
|
|
56
|
+
h+='<div style="display:flex;align-items:flex-start;gap:8px;padding:4px 0;border-bottom:1px solid #333;font-size:11px"><span style="color:'+lc+';width:44px;font-weight:600;font-size:10px;text-transform:uppercase;flex-shrink:0">'+escapeHtml(e.level||'')+'</span><span>'+escapeHtml(e.message||'')+'</span></div>';
|
|
78
57
|
}
|
|
79
58
|
continue;
|
|
80
59
|
}
|
|
81
|
-
if (
|
|
82
|
-
for (var
|
|
83
|
-
var g=
|
|
84
|
-
h+='<
|
|
60
|
+
if (f.type==='routes') {
|
|
61
|
+
for (var gi=0;gi<f.data.length;gi++) {
|
|
62
|
+
var g=f.data[gi];
|
|
63
|
+
h+='<div style="padding:5px 0 2px;font-weight:600;font-size:11px;color:#5d9">'+escapeHtml(g.method||'')+' <span style="color:#666;font-weight:400">('+(g.count||0)+')</span></div>';
|
|
85
64
|
if (g.routes) {
|
|
86
|
-
for (var
|
|
87
|
-
h+='<
|
|
65
|
+
for (var rj=0;rj<g.routes.length;rj++) {
|
|
66
|
+
h+='<div style="padding:2px 0 2px 14px;font-family:SF Mono,Menlo,monospace;font-size:11px">'+escapeHtml(g.routes[rj].path||'')+' <span style="color:#666">('+escapeHtml(g.routes[rj].controller||'')+')</span></div>';
|
|
88
67
|
}
|
|
89
68
|
}
|
|
90
69
|
}
|
|
91
70
|
continue;
|
|
92
71
|
}
|
|
93
|
-
if (
|
|
94
|
-
h+='<
|
|
95
|
-
h+='<tr><td colspan="2" style="padding:5px 8px"><pre style="font-family:ui-monospace,SF Mono,monospace;font-size:11px;color:${dimText};white-space:pre-wrap;margin:0;line-height:1.4">'+escapeHtml(v.stack||'')+'</pre></td></tr>';
|
|
72
|
+
if (f.type==='exception') {
|
|
73
|
+
h+='<div style="padding:8px;background:rgba(231,76,60,0.1);border-radius:4px"><div style="color:#e74c3c;font-weight:600;font-size:12px;margin-bottom:4px">'+escapeHtml(f.data.message||'')+'</div><pre style="font-family:SF Mono,Menlo,monospace;font-size:11px;color:#888;white-space:pre-wrap;margin:0;line-height:1.4">'+escapeHtml(f.data.stack||'')+'</pre></div>';
|
|
96
74
|
continue;
|
|
97
75
|
}
|
|
98
|
-
|
|
99
|
-
if (typeof v==='object' && v!==null) continue;
|
|
100
|
-
h+='<tr><td style="padding:4px 8px;color:${dimText};width:90px;vertical-align:top;font-size:11px">'+escapeHtml(k)+'</td><td style="padding:4px 8px;word-break:break-all;color:${labelFg}">'+escapeHtml(String(v))+'</td></tr>';
|
|
76
|
+
h+='<div style="display:flex;padding:3px 0;font-size:11px"><span style="color:#888;width:90px;flex-shrink:0">'+escapeHtml(f.key)+'</span><span style="word-break:break-all">'+escapeHtml(typeof f.val==='object'?JSON.stringify(f.val):String(f.val))+'</span></div>';
|
|
101
77
|
}
|
|
102
|
-
h+='</
|
|
78
|
+
h+='</div>';
|
|
103
79
|
pnl.innerHTML=h;
|
|
104
80
|
pnl.style.display='block';
|
|
105
|
-
D.getElementById(C+'-toggle').innerHTML='
|
|
81
|
+
D.getElementById(C+'-toggle').innerHTML='\u203a';
|
|
106
82
|
}
|
|
107
83
|
|
|
108
84
|
function escapeHtml(s) {
|
|
@@ -110,40 +86,37 @@ const TOOLBAR_TEMPLATE = (config) => {
|
|
|
110
86
|
return String(s).replace(/[&<>"]/g,function(m){return {'&':'&','<':'<','>':'>','"':'"'}[m]});
|
|
111
87
|
}
|
|
112
88
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
89
|
+
function makeBadge(html, cls) {
|
|
90
|
+
var el=D.createElement('span');
|
|
91
|
+
el.style.cssText='display:inline-flex;align-items:center;height:100%;padding:0 8px;color:#ccc;cursor:pointer;gap:4px;font-size:11px;border-right:1px solid #333;transition:background .1s';
|
|
92
|
+
el.innerHTML=html;
|
|
93
|
+
el.onmouseenter=function(){this.style.background='#333'};
|
|
94
|
+
el.onmouseleave=function(){this.style.background='transparent'};
|
|
95
|
+
if (cls) el.className=cls;
|
|
96
|
+
return el;
|
|
97
|
+
}
|
|
120
98
|
|
|
121
99
|
var furl = p + '/data';
|
|
122
100
|
fetch(furl).then(function(r){return r.json()}).then(function(d){
|
|
123
101
|
var bar=D.getElementById(C+'-bar');
|
|
124
102
|
var order=['request','performance','database','routes','logs'];
|
|
125
|
-
var
|
|
126
|
-
for(var oi=0;oi<order.length;oi++){if(d[order[oi]])
|
|
127
|
-
for(var k in d){var found=false;for(var pi=0;pi<
|
|
128
|
-
|
|
103
|
+
var items=[];
|
|
104
|
+
for(var oi=0;oi<order.length;oi++){if(d[order[oi]])items.push({key:order[oi],data:d[order[oi]]});}
|
|
105
|
+
for(var k in d){var found=false;for(var pi=0;pi<items.length;pi++){if(items[pi].key===k){found=true;break}}if(!found&&d[k]&&d[k].label)items.push({key:k,data:d[k]});}
|
|
106
|
+
items.forEach(function(item){
|
|
129
107
|
var p=item.data;
|
|
130
|
-
var
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
btn.innerHTML=ic+'<span>'+escapeHtml(p.summary)+'</span>';
|
|
134
|
-
btn.onmouseenter=function(){this.style.background='${btnHover}';this.style.color='${fg}'};
|
|
135
|
-
btn.onmouseleave=function(){this.style.background='${btnBg}';this.style.color='${btnFg}'};
|
|
136
|
-
btn.onclick=function(n){return function(){
|
|
137
|
-
var key=Object.keys(d).filter(function(kr){return d[kr]===d[n]})[0];
|
|
108
|
+
var badge=makeBadge('<span style="color:#888;font-weight:500">'+escapeHtml(p.summary)+'</span>');
|
|
109
|
+
badge.onclick=function(){
|
|
110
|
+
var key=Object.keys(d).filter(function(kr){return d[kr]===d[p]})[0];
|
|
138
111
|
renderPanel(key,d[key]);
|
|
139
|
-
}
|
|
140
|
-
bar.appendChild(
|
|
112
|
+
};
|
|
113
|
+
bar.appendChild(badge);
|
|
141
114
|
});
|
|
142
115
|
D.getElementById(C+'-toggle').onclick=function(){
|
|
143
116
|
var pnl=D.getElementById(C+'-panel');
|
|
144
117
|
var isOpen=pnl.style.display==='block';
|
|
145
118
|
pnl.style.display=isOpen?'none':'block';
|
|
146
|
-
this.innerHTML=isOpen?'
|
|
119
|
+
this.innerHTML=isOpen?'\u2039':'\u203a';
|
|
147
120
|
if(isOpen)lastActive=null;
|
|
148
121
|
};
|
|
149
122
|
}).catch(function(){});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template.js","sourceRoot":"","sources":["../../toolbar/template.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"template.js","sourceRoot":"","sources":["../../toolbar/template.ts"],"names":[],"mappings":";;;AAKO,MAAM,gBAAgB,GAAG,CAAC,MAAuC,EAAE,EAAE;IAC1E,MAAM,EAAE,QAAQ,GAAG,aAAa,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;IAClE,MAAM,EAAE,GAAG,gBAAgB,CAAC;IAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;IAC9C,MAAM,WAAW,GAAG,KAAK;QACvB,CAAC,CAAC,uCAAuC;QACzC,CAAC,CAAC,wCAAwC,CAAC;IAE7C,OAAO,eAAe,EAAE;;4CAEkB,GAAG;;;4CAGH,QAAQ,sIAAsI,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA0G3L,CAAC;AACX,CAAC,CAAC;AA1HW,QAAA,gBAAgB,oBA0H3B"}
|