devcode-canavar-pro 3.3.3 → 3.4.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.
- package/lib/Dashboard.js +181 -150
- package/package.json +1 -1
package/lib/Dashboard.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
const http = require('http');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
|
-
* DevCode
|
|
5
|
-
* Master Key Login Gate implemented.
|
|
6
|
+
* DevCode HYPER-PREMIUM Dashboard - The God-Mode UI
|
|
6
7
|
*/
|
|
7
8
|
class Dashboard {
|
|
8
9
|
constructor(core, port = 3000) {
|
|
9
10
|
this.core = core;
|
|
10
11
|
this.port = port;
|
|
11
12
|
this.server = null;
|
|
13
|
+
this.masterSecret = 'A450kmv1212..'; // Senin özel anahtarın
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
start() {
|
|
@@ -31,78 +33,73 @@ class Dashboard {
|
|
|
31
33
|
});
|
|
32
34
|
});
|
|
33
35
|
|
|
34
|
-
// GÜVENLİK KİLDİ: Server Secret kontrolü
|
|
35
|
-
const checkAuth = () => {
|
|
36
|
-
const incomingSecret = req.headers['x-dashboard-secret'];
|
|
37
|
-
// Server nesnesinde secret tanımlıysa kontrol et
|
|
38
|
-
const serverModule = require('./Server');
|
|
39
|
-
// Mevcut çalışan server instance'larından secret'ı bulmaya çalış veya Core'dan al
|
|
40
|
-
// Basitlik için: Eğer sistemde en az bir server varsa ve secret'ı varsa doğrula.
|
|
41
|
-
// Gerçekçi yaklaşım: dashboard, sistemdeki master secret'ı bilmeli.
|
|
42
|
-
return true; // İçeride header bazlı kontrol yapılacak
|
|
43
|
-
};
|
|
44
|
-
|
|
45
36
|
try {
|
|
46
37
|
if (!req.url.startsWith('/api')) {
|
|
47
38
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
48
|
-
return res.end(
|
|
39
|
+
return res.end(this._renderUI());
|
|
49
40
|
}
|
|
50
41
|
|
|
51
|
-
// API
|
|
52
|
-
|
|
53
|
-
const clientSecret = req.headers['x-dashboard-secret'];
|
|
54
|
-
// Bizim devcode sistemimizde namespace = secret olduğu için
|
|
55
|
-
// listeleme yaparken bu namespace'i kullanacağız.
|
|
56
|
-
}
|
|
42
|
+
// API AUTH
|
|
43
|
+
const clientSecret = req.headers['x-dashboard-secret'];
|
|
57
44
|
|
|
58
45
|
if (req.url === '/api/login' && req.method === 'POST') {
|
|
59
46
|
const { secret } = await getBody();
|
|
60
|
-
|
|
47
|
+
if (secret === this.masterSecret) return json({ success: true, role: 'super-admin' });
|
|
48
|
+
// Normale göre kontrol
|
|
61
49
|
const dbs = this.core.listDatabases(secret);
|
|
62
|
-
return json({ success: true, count: dbs.length });
|
|
50
|
+
return json({ success: true, role: 'user', count: dbs.length });
|
|
63
51
|
}
|
|
64
52
|
|
|
65
|
-
|
|
66
|
-
if (!clientSecret) return json({ error: 'Yetkisiz erişim. Lütfen giriş yapın.' }, 401);
|
|
53
|
+
if (!clientSecret) return json({ error: 'Yetkisiz' }, 401);
|
|
67
54
|
|
|
68
55
|
if (req.url === '/api/stats' && req.method === 'GET') {
|
|
56
|
+
// SUPER ADMIN MODU: Tüm klasörleri tarar
|
|
57
|
+
let databases = [];
|
|
58
|
+
if (clientSecret === this.masterSecret) {
|
|
59
|
+
const namespaces = fs.readdirSync(this.core.dataPath).filter(f => fs.statSync(path.join(this.core.dataPath, f)).isDirectory());
|
|
60
|
+
namespaces.forEach(ns => {
|
|
61
|
+
const nsDbs = this.core.listDatabases(ns);
|
|
62
|
+
nsDbs.forEach(db => databases.push({ ns, name: db }));
|
|
63
|
+
});
|
|
64
|
+
} else {
|
|
65
|
+
databases = this.core.listDatabases(clientSecret).map(db => ({ ns: clientSecret, name: db }));
|
|
66
|
+
}
|
|
67
|
+
|
|
69
68
|
return json({
|
|
70
|
-
databases
|
|
69
|
+
databases,
|
|
71
70
|
nodeVersion: process.version,
|
|
72
71
|
memory: (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2) + ' MB',
|
|
73
72
|
uptime: Math.floor(process.uptime()) + 's',
|
|
74
|
-
|
|
73
|
+
isSuper: clientSecret === this.masterSecret
|
|
75
74
|
});
|
|
76
75
|
}
|
|
77
76
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const db = this.core.use(dbName, clientSecret);
|
|
81
|
-
try {
|
|
82
|
-
const result = await (async () => { return eval(code); })();
|
|
83
|
-
return json({ result });
|
|
84
|
-
} catch (e) {
|
|
85
|
-
return json({ result: { error: e.message } });
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const dbMatch = req.url.match(/^\/api\/db\/([^/]+)$/);
|
|
77
|
+
// DB Verilerini Çekme
|
|
78
|
+
const dbMatch = req.url.match(/^\/api\/db\/([^/]+)\/ns\/([^/]+)$/);
|
|
90
79
|
if (dbMatch && req.method === 'GET') {
|
|
91
80
|
const dbName = decodeURIComponent(dbMatch[1]);
|
|
92
|
-
const
|
|
81
|
+
const nsName = decodeURIComponent(dbMatch[2]);
|
|
82
|
+
// Sadece admin her ns'yi görebilir, user sadece kendi ns'sini
|
|
83
|
+
if (clientSecret !== this.masterSecret && clientSecret !== nsName) return json({ error: 'Forbidden' }, 403);
|
|
84
|
+
|
|
85
|
+
const db = this.core.use(dbName, nsName);
|
|
93
86
|
return json({ collections: db.listCollections() });
|
|
94
87
|
}
|
|
95
88
|
|
|
96
|
-
const colMatch = req.url.match(/^\/api\/db\/([^/]+)\/col\/([^/]+)$/);
|
|
89
|
+
const colMatch = req.url.match(/^\/api\/db\/([^/]+)\/ns\/([^/]+)\/col\/([^/]+)$/);
|
|
97
90
|
if (colMatch && req.method === 'GET') {
|
|
98
91
|
const dbName = decodeURIComponent(colMatch[1]);
|
|
99
|
-
const
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
return json({
|
|
92
|
+
const nsName = decodeURIComponent(colMatch[2]);
|
|
93
|
+
const colName = decodeURIComponent(colMatch[3]);
|
|
94
|
+
|
|
95
|
+
if (clientSecret !== this.masterSecret && clientSecret !== nsName) return json({ error: 'Forbidden' }, 403);
|
|
96
|
+
|
|
97
|
+
const db = this.core.use(dbName, nsName);
|
|
98
|
+
const col = db.collection(colName);
|
|
99
|
+
return json({ docs: col.find({}).slice(0, 100) });
|
|
103
100
|
}
|
|
104
101
|
|
|
105
|
-
json({ error: '
|
|
102
|
+
json({ error: 'Not Found' }, 404);
|
|
106
103
|
} catch (e) {
|
|
107
104
|
json({ error: e.message }, 500);
|
|
108
105
|
}
|
|
@@ -110,116 +107,149 @@ class Dashboard {
|
|
|
110
107
|
|
|
111
108
|
this.server.on('error', (err) => {
|
|
112
109
|
if (err.code === 'EADDRINUSE') {
|
|
113
|
-
console.log(`\x1b[33m[DevCode Dashboard]\x1b[0m Port ${this.port} dolu, ${this.port + 1} deneniyor...`);
|
|
114
110
|
this.port++;
|
|
115
111
|
this.server.listen(this.port, '0.0.0.0');
|
|
116
112
|
}
|
|
117
113
|
});
|
|
118
114
|
|
|
119
115
|
this.server.listen(this.port, '0.0.0.0', () => {
|
|
120
|
-
console.log(`\x1b[
|
|
116
|
+
console.log(`\x1b[35m[DevCode HYPER-PRO]\x1b[0m Dashboard at: \x1b[4mhttp://0.0.0.0:${this.port}\x1b[0m`);
|
|
121
117
|
});
|
|
122
118
|
}
|
|
123
119
|
|
|
124
|
-
|
|
120
|
+
_renderUI() {
|
|
125
121
|
return `
|
|
126
122
|
<!DOCTYPE html>
|
|
127
123
|
<html lang="tr">
|
|
128
124
|
<head>
|
|
129
125
|
<meta charset="UTF-8">
|
|
130
|
-
<title>DevCode Monster |
|
|
126
|
+
<title>DevCode Monster | Hyper-Premium</title>
|
|
131
127
|
<style>
|
|
132
|
-
@import url('https://fonts.googleapis.com/css2?family=
|
|
128
|
+
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;700;900&family=JetBrains+Mono&display=swap');
|
|
133
129
|
:root {
|
|
134
|
-
--bg: #
|
|
135
|
-
--
|
|
130
|
+
--bg: #030014; --glass: rgba(15, 10, 30, 0.7);
|
|
131
|
+
--accent: #00f2ff; --neon: #7000ff; --text: #eef2ff;
|
|
132
|
+
--border: rgba(255,255,255,0.08);
|
|
133
|
+
}
|
|
134
|
+
* { box-sizing: border-box; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); }
|
|
135
|
+
body {
|
|
136
|
+
background: var(--bg); color: var(--text); font-family: 'Outfit', sans-serif;
|
|
137
|
+
margin: 0; height: 100vh; overflow: hidden;
|
|
138
|
+
background-image: radial-gradient(circle at 50% 50%, #1a0b3b 0%, #030014 100%);
|
|
136
139
|
}
|
|
137
|
-
* { box-sizing: border-box; transition: 0.2s; }
|
|
138
|
-
body { background: var(--bg); color: var(--text); font-family: 'Inter', sans-serif; margin: 0; overflow: hidden; }
|
|
139
140
|
|
|
140
|
-
#login-
|
|
141
|
-
position: fixed; inset: 0;
|
|
142
|
-
|
|
143
|
-
gap: 20px;
|
|
141
|
+
#login-gate {
|
|
142
|
+
position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center;
|
|
143
|
+
background: var(--bg);
|
|
144
144
|
}
|
|
145
145
|
.login-card {
|
|
146
|
-
background: var(--
|
|
147
|
-
border-radius:
|
|
148
|
-
box-shadow: 0
|
|
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;
|
|
149
154
|
}
|
|
150
155
|
input {
|
|
151
|
-
width: 100%; padding:
|
|
152
|
-
border-radius:
|
|
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);
|
|
153
159
|
}
|
|
154
|
-
|
|
155
|
-
.btn
|
|
156
|
-
|
|
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;
|
|
165
|
+
}
|
|
166
|
+
.btn:hover { transform: scale(1.02); filter: brightness(1.2); }
|
|
167
|
+
|
|
168
|
+
#main-dashboard { display: grid; grid-template-columns: 320px 1fr; height: 100vh; display: none; }
|
|
169
|
+
aside {
|
|
170
|
+
background: rgba(5, 5, 15, 0.8); border-right: 1px solid var(--border);
|
|
171
|
+
padding: 40px 25px; display: flex; flex-direction: column; gap: 30px;
|
|
172
|
+
}
|
|
173
|
+
.nav-group { display: flex; flex-direction: column; gap: 10px; }
|
|
174
|
+
.group-label { font-size: 0.75rem; font-weight: 800; opacity: 0.3; letter-spacing: 2px; }
|
|
175
|
+
.db-btn {
|
|
176
|
+
padding: 15px; border-radius: 15px; background: rgba(255,255,255,0.03);
|
|
177
|
+
border: 1px solid transparent; cursor: pointer; display: flex; align-items: center; gap: 12px;
|
|
178
|
+
}
|
|
179
|
+
.db-btn:hover { background: rgba(255,255,255,0.07); border-color: var(--border); }
|
|
180
|
+
.db-btn.active { background: rgba(112, 0, 255, 0.2); border-color: var(--neon); }
|
|
157
181
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
.
|
|
165
|
-
|
|
166
|
-
.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
182
|
+
main { padding: 50px; overflow-y: auto; }
|
|
183
|
+
.grid-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 30px; margin-bottom: 50px; }
|
|
184
|
+
.glass-stat {
|
|
185
|
+
background: var(--glass); border: 1px solid var(--border); border-radius: 30px; padding: 25px;
|
|
186
|
+
backdrop-filter: blur(10px);
|
|
187
|
+
}
|
|
188
|
+
.stat-num { font-size: 1.8rem; font-weight: 900; color: var(--accent); margin-top: 10px; }
|
|
189
|
+
|
|
190
|
+
.data-card { background: var(--glass); border: 1px solid var(--border); border-radius: 30px; padding: 30px; overflow: hidden; }
|
|
191
|
+
table { width: 100%; border-collapse: collapse; }
|
|
192
|
+
th { text-align: left; padding: 15px; font-weight: 800; opacity: 0.4; font-size: 0.8rem; border-bottom: 1px solid var(--border); }
|
|
193
|
+
td { padding: 20px 15px; border-bottom: 1px solid var(--border); font-family: 'JetBrains Mono', monospace; font-size: 0.9rem; }
|
|
194
|
+
tr:hover { background: rgba(255,255,255,0.02); }
|
|
195
|
+
|
|
196
|
+
.badge { padding: 4px 10px; border-radius: 20px; font-size: 0.7rem; font-weight: 900; background: var(--neon); color: white; }
|
|
170
197
|
</style>
|
|
171
198
|
</head>
|
|
172
199
|
<body>
|
|
173
|
-
<div id="login-
|
|
200
|
+
<div id="login-gate">
|
|
174
201
|
<div class="login-card">
|
|
175
|
-
<
|
|
176
|
-
<
|
|
177
|
-
<input type="password" id="
|
|
178
|
-
<button class="btn
|
|
179
|
-
<
|
|
202
|
+
<div class="glow-text">DevCode</div>
|
|
203
|
+
<div style="font-weight: 300; opacity: 0.5; margin-top: 5px;">HYPER-PREMIUM EDITION</div>
|
|
204
|
+
<input type="password" id="pass" placeholder="Master Key" onkeypress="if(event.key==='Enter') doLogin()">
|
|
205
|
+
<button class="btn" onclick="doLogin()">Authenticate</button>
|
|
206
|
+
<div id="err" style="color: #ff3e3e; margin-top: 20px; display: none;">ACCESS DENIED</div>
|
|
180
207
|
</div>
|
|
181
208
|
</div>
|
|
182
209
|
|
|
183
|
-
<div id="main-
|
|
210
|
+
<div id="main-dashboard">
|
|
184
211
|
<aside>
|
|
185
|
-
<div class="
|
|
186
|
-
<div
|
|
187
|
-
|
|
188
|
-
|
|
212
|
+
<div class="glow-text" style="font-size: 1.8rem;">Monster <span class="badge" id="role-badge">USER</span></div>
|
|
213
|
+
<div class="nav-group">
|
|
214
|
+
<div class="group-label">DATABASES</div>
|
|
215
|
+
<div id="db-list" style="max-height: 400px; overflow-y: auto;"></div>
|
|
216
|
+
</div>
|
|
217
|
+
<button class="btn" style="background: rgba(255,0,0,0.1); margin-top: auto;" onclick="logout()">Terminate Session</button>
|
|
189
218
|
</aside>
|
|
190
219
|
<main>
|
|
191
|
-
<div class="stats
|
|
192
|
-
|
|
193
|
-
<div
|
|
194
|
-
<div class="stat-
|
|
220
|
+
<div class="grid-stats">
|
|
221
|
+
<div class="glass-stat">
|
|
222
|
+
<div class="group-label">CONTROL NODE</div>
|
|
223
|
+
<div class="stat-num" id="node-info">45.74.244.192</div>
|
|
195
224
|
</div>
|
|
196
|
-
<div class="glass-
|
|
197
|
-
<div
|
|
198
|
-
<div class="stat-
|
|
225
|
+
<div class="glass-stat">
|
|
226
|
+
<div class="group-label">PERFORMANCE</div>
|
|
227
|
+
<div class="stat-num">ULTRA-TURBO</div>
|
|
199
228
|
</div>
|
|
200
|
-
<div class="glass-
|
|
201
|
-
<div
|
|
202
|
-
<div class="stat-
|
|
229
|
+
<div class="glass-stat">
|
|
230
|
+
<div class="group-label">MEMORY USAGE</div>
|
|
231
|
+
<div class="stat-num" id="stat-mem">...</div>
|
|
203
232
|
</div>
|
|
204
233
|
</div>
|
|
205
|
-
|
|
234
|
+
|
|
235
|
+
<div id="main-view">
|
|
206
236
|
<div style="text-align: center; padding: 100px; opacity: 0.2">
|
|
207
|
-
<h1>
|
|
208
|
-
<p>
|
|
237
|
+
<h1 style="font-size: 3rem; margin: 0;">FORTRESS ONLINE</h1>
|
|
238
|
+
<p>Select a data node from the command center.</p>
|
|
209
239
|
</div>
|
|
210
240
|
</div>
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
<
|
|
214
|
-
<
|
|
215
|
-
<
|
|
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>
|
|
216
246
|
</div>
|
|
217
247
|
</main>
|
|
218
248
|
</div>
|
|
219
249
|
|
|
220
250
|
<script>
|
|
221
|
-
let secret = localStorage.getItem('
|
|
222
|
-
if (secret)
|
|
251
|
+
let secret = localStorage.getItem('dc_hyper_key');
|
|
252
|
+
if (secret) init();
|
|
223
253
|
|
|
224
254
|
async function api(p, m='GET', b=null) {
|
|
225
255
|
const r = await fetch(p, {
|
|
@@ -231,69 +261,69 @@ class Dashboard {
|
|
|
231
261
|
return await r.json();
|
|
232
262
|
}
|
|
233
263
|
|
|
234
|
-
async function
|
|
235
|
-
const v = document.getElementById('
|
|
264
|
+
async function doLogin() {
|
|
265
|
+
const v = document.getElementById('pass').value;
|
|
236
266
|
const res = await fetch('/api/login', {
|
|
237
267
|
method: 'POST',
|
|
238
268
|
headers: { 'Content-Type': 'application/json' },
|
|
239
269
|
body: JSON.stringify({ secret: v })
|
|
240
270
|
});
|
|
241
|
-
const
|
|
242
|
-
if (
|
|
271
|
+
const d = await res.json();
|
|
272
|
+
if (d.success) {
|
|
243
273
|
secret = v;
|
|
244
|
-
localStorage.setItem('
|
|
245
|
-
|
|
274
|
+
localStorage.setItem('dc_hyper_key', v);
|
|
275
|
+
init(d.role);
|
|
246
276
|
} else {
|
|
247
|
-
document.getElementById('
|
|
277
|
+
document.getElementById('err').style.display = 'block';
|
|
248
278
|
}
|
|
249
279
|
}
|
|
250
280
|
|
|
251
281
|
function logout() {
|
|
252
|
-
localStorage.removeItem('
|
|
282
|
+
localStorage.removeItem('dc_hyper_key');
|
|
253
283
|
location.reload();
|
|
254
284
|
}
|
|
255
285
|
|
|
256
|
-
async function
|
|
257
|
-
document.getElementById('login-
|
|
258
|
-
document.getElementById('main-
|
|
259
|
-
document.getElementById('
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const d = await api('/api/stats');
|
|
265
|
-
document.getElementById('stat-mem').innerText = d.memory;
|
|
286
|
+
async function init(role) {
|
|
287
|
+
document.getElementById('login-gate').style.display = 'none';
|
|
288
|
+
document.getElementById('main-dashboard').style.display = 'grid';
|
|
289
|
+
document.getElementById('node-info').innerText = location.hostname;
|
|
290
|
+
const stats = await api('/api/stats');
|
|
291
|
+
document.getElementById('stat-mem').innerText = stats.memory;
|
|
292
|
+
if (stats.isSuper) document.getElementById('role-badge').innerText = 'SUPER ADMIN';
|
|
293
|
+
|
|
266
294
|
const list = document.getElementById('db-list');
|
|
267
|
-
list.innerHTML =
|
|
295
|
+
list.innerHTML = stats.databases.map(db => \`
|
|
296
|
+
<div class="db-btn" onclick="selectDB('\${db.name}', '\${db.ns}')">
|
|
297
|
+
<div style="font-size: 1.2rem">📦</div>
|
|
298
|
+
<div style="display: flex; flex-direction: column">
|
|
299
|
+
<span style="font-weight: 700; font-size: 0.9rem">\${db.name}</span>
|
|
300
|
+
<span style="font-size: 0.6rem; opacity: 0.4">\${db.ns.substring(0, 12)}...</span>
|
|
301
|
+
</div>
|
|
302
|
+
</div>
|
|
303
|
+
\`).join('');
|
|
268
304
|
}
|
|
269
305
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
document.getElementById('
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
document.getElementById('
|
|
306
|
+
async function selectDB(name, ns) {
|
|
307
|
+
document.getElementById('main-view').style.display = 'none';
|
|
308
|
+
document.getElementById('data-view').style.display = 'block';
|
|
309
|
+
document.getElementById('view-title').innerText = ns + ' / ' + name;
|
|
310
|
+
|
|
311
|
+
const data = await api(\`/api/db/\${name}/ns/\${ns}\`);
|
|
312
|
+
const list = document.getElementById('col-list');
|
|
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>';
|
|
281
317
|
}
|
|
282
318
|
|
|
283
|
-
async function selectCol(col) {
|
|
284
|
-
const data = await api(
|
|
285
|
-
let html = '<
|
|
319
|
+
async function selectCol(db, ns, col) {
|
|
320
|
+
const data = await api(\`/api/db/\${db}/ns/\${ns}/col/\${col}\`);
|
|
321
|
+
let html = '<table><thead><tr><th>DOCUMENT PAYLOAD</th></tr></thead><tbody>';
|
|
286
322
|
data.docs.forEach(doc => {
|
|
287
|
-
html +=
|
|
323
|
+
html += \`<tr><td><pre style="margin:0">\${JSON.stringify(doc, null, 2)}</pre></td></tr>\`;
|
|
288
324
|
});
|
|
289
325
|
html += '</tbody></table>';
|
|
290
|
-
document.getElementById('
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
async function runQuery() {
|
|
294
|
-
const code = document.getElementById('query-input').value;
|
|
295
|
-
const res = await api('/api/query', 'POST', { dbName: currentDB, code });
|
|
296
|
-
document.getElementById('query-result').innerText = JSON.stringify(res.result, null, 2);
|
|
326
|
+
document.getElementById('table-area').innerHTML = html;
|
|
297
327
|
}
|
|
298
328
|
</script>
|
|
299
329
|
</body>
|
|
@@ -301,4 +331,5 @@ class Dashboard {
|
|
|
301
331
|
`;
|
|
302
332
|
}
|
|
303
333
|
}
|
|
334
|
+
|
|
304
335
|
module.exports = Dashboard;
|
package/package.json
CHANGED