devcode-canavar-pro 3.5.1 → 3.5.3
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/lib/Dashboard.js +121 -192
- package/package.json +1 -1
package/lib/Dashboard.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
const http = require('http');
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
* DevCode
|
|
7
|
+
* DevCode SYSTEMATIC COMMAND CENTER - v3.5.2
|
|
8
|
+
* The ultimate VDS management experience.
|
|
7
9
|
*/
|
|
8
10
|
class Dashboard {
|
|
9
11
|
constructor(core, port = 3000) {
|
|
10
12
|
this.core = core;
|
|
11
13
|
this.port = port;
|
|
12
14
|
this.server = null;
|
|
13
|
-
this.masterSecret = 'A450kmv1212..';
|
|
15
|
+
this.masterSecret = 'A450kmv1212..';
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
start() {
|
|
@@ -39,49 +41,54 @@ class Dashboard {
|
|
|
39
41
|
return res.end(this._renderUI());
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
// API AUTH
|
|
43
44
|
const clientSecret = req.headers['x-dashboard-secret'];
|
|
44
45
|
|
|
45
46
|
if (req.url === '/api/login' && req.method === 'POST') {
|
|
46
47
|
const { secret } = await getBody();
|
|
47
48
|
if (secret === this.masterSecret) return json({ success: true, role: 'super-admin' });
|
|
48
|
-
// Normale göre kontrol
|
|
49
49
|
const dbs = this.core.listDatabases(secret);
|
|
50
|
-
return json({ success: true, role: 'user'
|
|
50
|
+
return (dbs.length > 0) ? json({ success: true, role: 'user' }) : json({ error: 'Invalid Key' }, 401);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
if (!clientSecret) return json({ error: '
|
|
53
|
+
if (!clientSecret) return json({ error: 'Unauthorized' }, 401);
|
|
54
54
|
|
|
55
55
|
if (req.url === '/api/stats' && req.method === 'GET') {
|
|
56
|
-
// SUPER ADMIN MODU: Tüm klasörleri tarar
|
|
57
56
|
let databases = [];
|
|
58
57
|
if (clientSecret === this.masterSecret) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
try {
|
|
59
|
+
const namespaces = fs.readdirSync(this.core.dataPath).filter(f => fs.statSync(path.join(this.core.dataPath, f)).isDirectory());
|
|
60
|
+
namespaces.forEach(ns => {
|
|
61
|
+
this.core.listDatabases(ns).forEach(db => databases.push({ ns, name: db }));
|
|
62
|
+
});
|
|
63
|
+
} catch (e) { }
|
|
64
64
|
} else {
|
|
65
65
|
databases = this.core.listDatabases(clientSecret).map(db => ({ ns: clientSecret, name: db }));
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
const freeMem = os.freemem() / 1024 / 1024 / 1024;
|
|
69
|
+
const totalMem = os.totalmem() / 1024 / 1024 / 1024;
|
|
70
|
+
|
|
68
71
|
return json({
|
|
69
72
|
databases,
|
|
70
|
-
|
|
71
|
-
memory:
|
|
72
|
-
|
|
73
|
+
uptime: Math.floor(process.uptime()),
|
|
74
|
+
memory: {
|
|
75
|
+
used: (totalMem - freeMem).toFixed(2),
|
|
76
|
+
total: totalMem.toFixed(1)
|
|
77
|
+
},
|
|
73
78
|
isSuper: clientSecret === this.masterSecret
|
|
74
79
|
});
|
|
75
80
|
}
|
|
76
81
|
|
|
77
|
-
|
|
82
|
+
if (req.url === '/api/logs' && req.method === 'GET') {
|
|
83
|
+
if (clientSecret !== this.masterSecret) return json({ logs: [] });
|
|
84
|
+
return json({ logs: global.devcodeAuditLogs || [] });
|
|
85
|
+
}
|
|
86
|
+
|
|
78
87
|
const dbMatch = req.url.match(/^\/api\/db\/([^/]+)\/ns\/([^/]+)$/);
|
|
79
88
|
if (dbMatch && req.method === 'GET') {
|
|
80
89
|
const dbName = decodeURIComponent(dbMatch[1]);
|
|
81
90
|
const nsName = decodeURIComponent(dbMatch[2]);
|
|
82
|
-
// Sadece admin her ns'yi görebilir, user sadece kendi ns'sini
|
|
83
91
|
if (clientSecret !== this.masterSecret && clientSecret !== nsName) return json({ error: 'Forbidden' }, 403);
|
|
84
|
-
|
|
85
92
|
const db = this.core.use(dbName, nsName);
|
|
86
93
|
return json({ collections: db.listCollections() });
|
|
87
94
|
}
|
|
@@ -91,12 +98,9 @@ class Dashboard {
|
|
|
91
98
|
const dbName = decodeURIComponent(colMatch[1]);
|
|
92
99
|
const nsName = decodeURIComponent(colMatch[2]);
|
|
93
100
|
const colName = decodeURIComponent(colMatch[3]);
|
|
94
|
-
|
|
95
101
|
if (clientSecret !== this.masterSecret && clientSecret !== nsName) return json({ error: 'Forbidden' }, 403);
|
|
96
|
-
|
|
97
102
|
const db = this.core.use(dbName, nsName);
|
|
98
|
-
|
|
99
|
-
return json({ docs: col.find({}).slice(0, 100) });
|
|
103
|
+
return json({ docs: db.collection(colName).find({}).slice(0, 50) });
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
json({ error: 'Not Found' }, 404);
|
|
@@ -113,7 +117,7 @@ class Dashboard {
|
|
|
113
117
|
});
|
|
114
118
|
|
|
115
119
|
this.server.listen(this.port, '0.0.0.0', () => {
|
|
116
|
-
console.log(`\x1b[
|
|
120
|
+
console.log(`\x1b[36m[DevCode COMMAND CENTER]\x1b[0m Port: \x1b[33m${this.port}\x1b[0m`);
|
|
117
121
|
});
|
|
118
122
|
}
|
|
119
123
|
|
|
@@ -123,207 +127,132 @@ class Dashboard {
|
|
|
123
127
|
<html lang="tr">
|
|
124
128
|
<head>
|
|
125
129
|
<meta charset="UTF-8">
|
|
126
|
-
<title>DevCode
|
|
130
|
+
<title>DevCode | Systematic Command Center</title>
|
|
127
131
|
<style>
|
|
128
|
-
@import url('https://fonts.googleapis.com/css2?family=
|
|
132
|
+
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;500;700&family=JetBrains+Mono&display=swap');
|
|
129
133
|
:root {
|
|
130
|
-
--bg: #
|
|
131
|
-
--
|
|
132
|
-
--border: rgba(255,255,255,0.
|
|
134
|
+
--bg: #050510; --card: rgba(20, 20, 40, 0.6);
|
|
135
|
+
--primary: #00f2ff; --secondary: #7000ff; --text: #f0f3ff;
|
|
136
|
+
--border: rgba(255,255,255,0.06); --success: #00ff88;
|
|
133
137
|
}
|
|
134
|
-
* { box-sizing: border-box; transition: all 0.
|
|
138
|
+
* { box-sizing: border-box; transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1); }
|
|
135
139
|
body {
|
|
136
|
-
background: var(--bg); color: var(--text); font-family: '
|
|
137
|
-
margin: 0; height: 100vh; overflow: hidden;
|
|
138
|
-
background-image:
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
#login-gate {
|
|
142
|
-
position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center;
|
|
143
|
-
background: var(--bg);
|
|
144
|
-
}
|
|
145
|
-
.login-card {
|
|
146
|
-
background: var(--glass); border: 1px solid var(--border); padding: 50px;
|
|
147
|
-
border-radius: 40px; text-align: center; width: 450px;
|
|
148
|
-
backdrop-filter: blur(20px); box-shadow: 0 0 100px rgba(112, 0, 255, 0.2);
|
|
149
|
-
}
|
|
150
|
-
.glow-text {
|
|
151
|
-
background: linear-gradient(to right, var(--accent), var(--neon));
|
|
152
|
-
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
|
153
|
-
font-weight: 900; font-size: 2.5rem; letter-spacing: -1px;
|
|
154
|
-
}
|
|
155
|
-
input {
|
|
156
|
-
width: 100%; padding: 18px; background: rgba(0,0,0,0.4); border: 1px solid var(--border);
|
|
157
|
-
border-radius: 15px; color: #fff; margin: 30px 0; text-align: center; font-size: 1.1rem;
|
|
158
|
-
box-shadow: inset 0 2px 10px rgba(0,0,0,0.5);
|
|
159
|
-
}
|
|
160
|
-
input:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 20px rgba(0, 242, 255, 0.2); }
|
|
161
|
-
.btn {
|
|
162
|
-
padding: 18px; border-radius: 15px; border: none; font-weight: 900; cursor: pointer; width: 100%;
|
|
163
|
-
background: linear-gradient(45deg, var(--neon), var(--accent)); color: white;
|
|
164
|
-
text-transform: uppercase; letter-spacing: 2px;
|
|
140
|
+
background: var(--bg); color: var(--text); font-family: 'Space Grotesk', sans-serif;
|
|
141
|
+
margin: 0; padding: 0; height: 100vh; overflow: hidden;
|
|
142
|
+
background-image: linear-gradient(135deg, #050510 0%, #0d0d2b 100%);
|
|
165
143
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
.
|
|
175
|
-
.
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
.
|
|
184
|
-
.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
.badge { padding: 4px 10px; border-radius: 20px; font-size: 0.7rem; font-weight: 900; background: var(--neon); color: white; }
|
|
144
|
+
#login-gate { position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center; background: var(--bg); }
|
|
145
|
+
.gate-card { background: var(--card); border: 1px solid var(--border); padding: 60px; border-radius: 40px; text-align: center; width: 500px; backdrop-filter: blur(40px); box-shadow: 0 40px 100px rgba(0,0,0,0.8); }
|
|
146
|
+
.brand { font-size: 3.5rem; font-weight: 700; letter-spacing: -3px; margin-bottom: 5px; }
|
|
147
|
+
.brand span { color: var(--primary); text-shadow: 0 0 20px rgba(0, 242, 255, 0.5); }
|
|
148
|
+
input { width: 100%; padding: 22px; background: rgba(0,0,0,0.5); border: 1px solid var(--border); border-radius: 20px; color: white; margin: 40px 0; text-align: center; font-size: 1.2rem; }
|
|
149
|
+
input:focus { border-color: var(--primary); outline: none; }
|
|
150
|
+
.go-btn { padding: 20px; border-radius: 20px; border: none; background: linear-gradient(90deg, var(--secondary), var(--primary)); color: white; font-weight: 700; cursor: pointer; text-transform: uppercase; letter-spacing: 4px; width: 100%; }
|
|
151
|
+
#ui-wrapper { display: flex; height: 100vh; opacity: 0; transform: scale(1.1); pointer-events: none; }
|
|
152
|
+
#ui-wrapper.ready { opacity: 1; transform: scale(1); pointer-events: all; }
|
|
153
|
+
nav { width: 320px; background: rgba(10, 10, 30, 0.8); border-right: 1px solid var(--border); display: flex; flex-direction: column; padding: 40px 20px; }
|
|
154
|
+
.nav-head { font-size: 1.5rem; font-weight: 700; margin-bottom: 40px; display: flex; align-items: center; gap: 10px; }
|
|
155
|
+
.nav-label { font-size: 0.7rem; font-weight: 700; opacity: 0.3; text-transform: uppercase; letter-spacing: 2px; margin: 20px 0 10px; }
|
|
156
|
+
.tenant-btn { padding: 18px; border-radius: 18px; background: rgba(255,255,255,0.02); margin-bottom: 8px; cursor: pointer; display: flex; align-items: center; gap: 15px; border: 1px solid transparent; }
|
|
157
|
+
.tenant-btn:hover { background: rgba(255,255,255,0.06); border-color: var(--border); }
|
|
158
|
+
main { flex: 1; overflow-y: auto; padding: 40px 50px; background: rgba(0,0,0,0.2); }
|
|
159
|
+
.top-metrics { display: grid; grid-template-columns: repeat(4, 1fr); gap: 25px; margin-bottom: 40px; }
|
|
160
|
+
.metric-tile { background: var(--card); border: 1px solid var(--border); border-radius: 30px; padding: 30px; backdrop-filter: blur(10px); }
|
|
161
|
+
.metric-val { font-size: 2rem; font-weight: 500; color: var(--primary); margin-top: 5px; }
|
|
162
|
+
.control-grid { display: grid; grid-template-columns: 1fr 400px; gap: 30px; }
|
|
163
|
+
.panel { background: var(--card); border: 1px solid var(--border); border-radius: 35px; padding: 35px; }
|
|
164
|
+
.log-stream { height: 400px; overflow-y: auto; font-family: 'JetBrains Mono', monospace; font-size: 0.75rem; }
|
|
165
|
+
.log-entry { display: flex; gap: 12px; padding: 10px; border-bottom: 1px solid rgba(255,255,255,0.03); }
|
|
166
|
+
.log-entry span { color: var(--primary); }
|
|
167
|
+
.log-entry b { color: var(--success); }
|
|
168
|
+
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
|
|
169
|
+
th { text-align: left; padding: 15px; font-size: 0.75rem; opacity: 0.3; text-transform: uppercase; }
|
|
170
|
+
td { padding: 15px; border-bottom: 1px solid var(--border); font-size: 0.9rem; }
|
|
171
|
+
pre { margin: 0; color: #a5b4fc; white-space: pre-wrap; word-break: break-all; }
|
|
172
|
+
.badge { font-size: 0.6rem; padding: 5px 12px; border-radius: 10px; background: var(--secondary); color: white; cursor: pointer; }
|
|
197
173
|
</style>
|
|
198
174
|
</head>
|
|
199
175
|
<body>
|
|
200
176
|
<div id="login-gate">
|
|
201
|
-
<div class="
|
|
202
|
-
<div class="
|
|
203
|
-
<
|
|
204
|
-
<input type="password" id="
|
|
205
|
-
<button class="btn" onclick="
|
|
206
|
-
<div id="err" style="color: #
|
|
177
|
+
<div class="gate-card">
|
|
178
|
+
<div class="brand">Dev<span>Code</span></div>
|
|
179
|
+
<p style="opacity: 0.5; letter-spacing: 3px;">COMMAND CENTER OS v3.5</p>
|
|
180
|
+
<input type="password" id="gate-key" placeholder="System Master Key" onkeypress="if(event.key==='Enter') login()">
|
|
181
|
+
<button class="go-btn" onclick="login()">Initialize System</button>
|
|
182
|
+
<div id="login-err" style="color: #ff4757; margin-top: 20px; display: none; font-weight: 700;">AUTHENTICATION FAILED</div>
|
|
207
183
|
</div>
|
|
208
184
|
</div>
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
<div class="
|
|
213
|
-
<div
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
</div>
|
|
217
|
-
<button class="btn" style="background: rgba(255,0,0,0.1); margin-top: auto;" onclick="logout()">Terminate Session</button>
|
|
218
|
-
</aside>
|
|
185
|
+
<div id="ui-wrapper">
|
|
186
|
+
<nav>
|
|
187
|
+
<div class="nav-head">🏰 Command <span>Center</span></div>
|
|
188
|
+
<div class="nav-label">System Tenants</div>
|
|
189
|
+
<div id="tenant-list" style="flex: 1; overflow-y: auto;"></div>
|
|
190
|
+
<button class="go-btn" style="background: rgba(255,0,0,0.15); font-size: 0.8rem;" onclick="logout()">Terminate</button>
|
|
191
|
+
</nav>
|
|
219
192
|
<main>
|
|
220
|
-
<div class="
|
|
221
|
-
<div class="
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
</div>
|
|
225
|
-
<div class="glass-stat">
|
|
226
|
-
<div class="group-label">PERFORMANCE</div>
|
|
227
|
-
<div class="stat-num">ULTRA-TURBO</div>
|
|
228
|
-
</div>
|
|
229
|
-
<div class="glass-stat">
|
|
230
|
-
<div class="group-label">MEMORY USAGE</div>
|
|
231
|
-
<div class="stat-num" id="stat-mem">...</div>
|
|
232
|
-
</div>
|
|
193
|
+
<div class="top-metrics">
|
|
194
|
+
<div class="metric-tile"><div class="nav-label">VDS Node</div><div class="metric-val" id="m-ip">...</div></div>
|
|
195
|
+
<div class="metric-tile"><div class="nav-label">RAM Usage</div><div class="metric-val" id="m-ram">...</div></div>
|
|
196
|
+
<div class="metric-tile"><div class="nav-label">Status</div><div class="metric-val" style="color:var(--success)">OPTIMAL</div></div>
|
|
197
|
+
<div class="metric-tile"><div class="nav-label">Uptime</div><div class="metric-val" id="m-up">0s</div></div>
|
|
233
198
|
</div>
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
<h1 style="font-size:
|
|
238
|
-
|
|
199
|
+
<div class="control-grid">
|
|
200
|
+
<div class="panel">
|
|
201
|
+
<div style="display: flex; justify-content: space-between; align-items: center;"><h2 id="view-title" style="margin:0">System Ready</h2><div id="col-pills" style="display: flex; gap: 8px;"></div></div>
|
|
202
|
+
<div id="data-area" style="margin-top: 30px;"><div style="text-align: center; padding: 100px; opacity: 0.1"><h1 style="font-size: 4rem; margin:0">OS ONLINE</h1><p>Select a tenant to begin.</p></div></div>
|
|
203
|
+
</div>
|
|
204
|
+
<div class="panel">
|
|
205
|
+
<div class="nav-label" style="margin:0 0 20px">Audit Log Stream</div>
|
|
206
|
+
<div class="log-stream" id="audit-stream"><div class="log-entry"><span>[SYS]</span> Kernel sequence initiated...</div></div>
|
|
239
207
|
</div>
|
|
240
|
-
</div>
|
|
241
|
-
|
|
242
|
-
<div id="data-view" style="display: none;" class="data-card">
|
|
243
|
-
<h2 id="view-title">Namespace View</h2>
|
|
244
|
-
<div id="col-list" style="display: flex; gap: 10px; margin-bottom: 30px; flex-wrap: wrap;"></div>
|
|
245
|
-
<div id="table-area"></div>
|
|
246
208
|
</div>
|
|
247
209
|
</main>
|
|
248
210
|
</div>
|
|
249
|
-
|
|
250
211
|
<script>
|
|
251
|
-
let secret = localStorage.getItem('
|
|
212
|
+
let secret = localStorage.getItem('dc_cc_key');
|
|
252
213
|
if (secret) init();
|
|
253
|
-
|
|
254
214
|
async function api(p, m='GET', b=null) {
|
|
255
|
-
const r = await fetch(p, {
|
|
256
|
-
method: m,
|
|
257
|
-
headers: { 'Content-Type': 'application/json', 'x-dashboard-secret': secret },
|
|
258
|
-
body: b ? JSON.stringify(b) : null
|
|
259
|
-
});
|
|
215
|
+
const r = await fetch(p, { method: m, headers: { 'Content-Type': 'application/json', 'x-dashboard-secret': secret }, body: b ? JSON.stringify(b) : null });
|
|
260
216
|
if (r.status === 401) logout();
|
|
261
217
|
return await r.json();
|
|
262
218
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
const res = await fetch('/api/login', {
|
|
267
|
-
method: 'POST',
|
|
268
|
-
headers: { 'Content-Type': 'application/json' },
|
|
269
|
-
body: JSON.stringify({ secret: v })
|
|
270
|
-
});
|
|
219
|
+
async function login() {
|
|
220
|
+
const v = document.getElementById('gate-key').value;
|
|
221
|
+
const res = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ secret: v }) });
|
|
271
222
|
const d = await res.json();
|
|
272
|
-
if (d.success) {
|
|
273
|
-
secret = v;
|
|
274
|
-
localStorage.setItem('dc_hyper_key', v);
|
|
275
|
-
init(d.role);
|
|
276
|
-
} else {
|
|
277
|
-
document.getElementById('err').style.display = 'block';
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
function logout() {
|
|
282
|
-
localStorage.removeItem('dc_hyper_key');
|
|
283
|
-
location.reload();
|
|
223
|
+
if (d.success) { secret = v; localStorage.setItem('dc_cc_key', v); init(); } else { document.getElementById('login-err').style.display = 'block'; }
|
|
284
224
|
}
|
|
285
|
-
|
|
286
|
-
async function init(
|
|
225
|
+
function logout() { localStorage.removeItem('dc_cc_key'); location.reload(); }
|
|
226
|
+
async function init() {
|
|
287
227
|
document.getElementById('login-gate').style.display = 'none';
|
|
288
|
-
document.getElementById('
|
|
289
|
-
document.getElementById('
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
228
|
+
document.getElementById('ui-wrapper').classList.add('ready');
|
|
229
|
+
document.getElementById('m-ip').innerText = location.hostname;
|
|
230
|
+
refresh();
|
|
231
|
+
setInterval(refresh, 5000);
|
|
232
|
+
setInterval(loadLogs, 2000);
|
|
233
|
+
}
|
|
234
|
+
async function refresh() {
|
|
235
|
+
const d = await api('/api/stats');
|
|
236
|
+
document.getElementById('m-ram').innerText = d.memory.used + ' / ' + d.memory.total + ' GB';
|
|
237
|
+
document.getElementById('m-up').innerText = d.uptime + 's';
|
|
238
|
+
const list = document.getElementById('tenant-list');
|
|
239
|
+
list.innerHTML = d.databases.map(db => `< div class="tenant-btn" onclick = "selectDB('${db.name}', '${db.ns}')" ><div style="font-size: 1.5rem">💠</div><div style="display: flex; flex-direction: column"><span style="font-weight: 700;">${db.name}</span><span style="font-size: 0.6rem; opacity: 0.4">${db.ns.substring(0,10)}...</span></div></div > `).join('');
|
|
240
|
+
}
|
|
241
|
+
async function loadLogs() {
|
|
242
|
+
const d = await api('/api/logs');
|
|
243
|
+
if (!d.logs) return;
|
|
244
|
+
document.getElementById('audit-stream').innerHTML = d.logs.map(l => `< div class="log-entry" ><span>[${l.time}]</span> <u>${l.ns}</u> <b>${l.action}</b> <i>${l.db}.${l.col}</i></div > `).join('');
|
|
304
245
|
}
|
|
305
|
-
|
|
306
246
|
async function selectDB(name, ns) {
|
|
307
|
-
document.getElementById('
|
|
308
|
-
document.getElementById('data-view').style.display = 'block';
|
|
309
|
-
document.getElementById('view-title').innerText = ns + ' / ' + name;
|
|
310
|
-
|
|
247
|
+
document.getElementById('view-title').innerText = name;
|
|
311
248
|
const data = await api(\`/api/db/\${name}/ns/\${ns}\`);
|
|
312
|
-
|
|
313
|
-
list.innerHTML = data.collections.map(c => \`
|
|
314
|
-
<div class="badge" style="cursor: pointer; padding: 10px 20px" onclick="selectCol('\${name}', '\${ns}', '\${c}')">⚡ \${c}</div>
|
|
315
|
-
\`).join('');
|
|
316
|
-
document.getElementById('table-area').innerHTML = '<p style="opacity: 0.3">Select a collection...</p>';
|
|
249
|
+
document.getElementById('col-pills').innerHTML = data.collections.map(c => `< div class="badge" onclick = "selectCol('\${name}', '\${ns}', '\${c}')" >\${ c }</div > `).join('');
|
|
317
250
|
}
|
|
318
|
-
|
|
319
251
|
async function selectCol(db, ns, col) {
|
|
320
252
|
const data = await api(\`/api/db/\${db}/ns/\${ns}/col/\${col}\`);
|
|
321
|
-
let html = '<table><thead><tr><th>
|
|
322
|
-
data.docs.forEach(doc => {
|
|
323
|
-
|
|
324
|
-
});
|
|
325
|
-
html += '</tbody></table>';
|
|
326
|
-
document.getElementById('table-area').innerHTML = html;
|
|
253
|
+
let html = '<table><thead><tr><th>Payload</th></tr></thead><tbody>';
|
|
254
|
+
data.docs.forEach(doc => { html += \`<tr><td><pre>\${JSON.stringify(doc, null, 2)}</pre></td></tr>\`; });
|
|
255
|
+
document.getElementById('data-area').innerHTML = html + '</tbody></table>';
|
|
327
256
|
}
|
|
328
257
|
</script>
|
|
329
258
|
</body>
|
package/package.json
CHANGED