@aimeloic/monkey-tester 4.0.5 → 4.0.6
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/htmlTemplate.js +11 -21
- package/package.json +1 -1
package/htmlTemplate.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// Original Sandbox Runtime — Stringified safely to browser context
|
|
4
3
|
function runtimeClientSandbox() {
|
|
5
4
|
const ENDPOINTS = JSON.parse(atob(document.getElementById('__monkey_data__').getAttribute('data-payload')));
|
|
6
5
|
let currentKey = null;
|
|
7
6
|
|
|
8
7
|
document.getElementById('base-url').value = window.location.origin;
|
|
9
8
|
|
|
10
|
-
// Auto-paste Token directly if it exists in local storage
|
|
11
9
|
const savedToken = localStorage.getItem('__auth_token__');
|
|
12
10
|
if (savedToken) {
|
|
13
11
|
document.getElementById('jwt-input').value = savedToken;
|
|
@@ -151,7 +149,6 @@ function runtimeClientSandbox() {
|
|
|
151
149
|
buildSidebar();
|
|
152
150
|
}
|
|
153
151
|
|
|
154
|
-
// Global UI layouts object
|
|
155
152
|
const UI = {
|
|
156
153
|
tester: (endpointsJsonB64) => `<!DOCTYPE html>
|
|
157
154
|
<html lang="en">
|
|
@@ -232,8 +229,8 @@ const UI = {
|
|
|
232
229
|
button { background: #e8a838; color: #0e0c09; border: none; padding: 12px; width: 100%; border-radius: 6px; font-weight: 600; cursor: pointer; margin-top: 10px; }
|
|
233
230
|
.footer { text-align: center; margin-top: 20px; font-size: 13px; color: #9a8c78; } a { color: #e8a838; text-decoration: none; }</style></head>
|
|
234
231
|
<body><div class="card"><h2>Sign In</h2><div id="err" style="color:#d45c3c; font-size:13px; margin-bottom:15px; text-align:center;"></div>
|
|
235
|
-
<div class="field"><label>Email</label><input type="email" id="email" value="
|
|
236
|
-
<div class="field"><label>Password</label><input type="password" id="password" value="
|
|
232
|
+
<div class="field"><label>Email</label><input type="email" id="email" value="admin@bakery.com"></div>
|
|
233
|
+
<div class="field"><label>Password</label><input type="password" id="password" value="password123"></div>
|
|
237
234
|
<button onclick="handleLogin()">Log In</button><div class="footer">Need an account? <a href="/signup">Sign up</a></div></div>
|
|
238
235
|
<script>async function handleLogin() {
|
|
239
236
|
const email = document.getElementById('email').value;
|
|
@@ -271,7 +268,6 @@ const UI = {
|
|
|
271
268
|
} else { msgDiv.style.color = '#d45c3c'; msgDiv.textContent = data.error || 'Registration failed'; }
|
|
272
269
|
}</script></body></html>`,
|
|
273
270
|
|
|
274
|
-
// DYNAMIC CRUD DASHBOARD — Reads fields and paths from runtime ENDPOINTS definition instead of static products paths
|
|
275
271
|
dashboard: (endpointsJsonB64) => `<!DOCTYPE html><html><head><title>Dynamic Admin Dashboard</title>
|
|
276
272
|
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&display=swap" rel="stylesheet">
|
|
277
273
|
<style>
|
|
@@ -306,7 +302,7 @@ const UI = {
|
|
|
306
302
|
<body>
|
|
307
303
|
<div id="__monkey_data__" data-payload="${endpointsJsonB64}" style="display:none;"></div>
|
|
308
304
|
<header>
|
|
309
|
-
<h1
|
|
305
|
+
<h1>Universal Management Dashboard</h1>
|
|
310
306
|
<div class="nav-links">
|
|
311
307
|
<a href="/api/tester" target="_blank">🛠 Open Tester Sandbox</a>
|
|
312
308
|
<button class="logout-btn" onclick="localStorage.removeItem('__auth_token__'); window.location.href='/login'">Log Out</button>
|
|
@@ -343,10 +339,8 @@ const UI = {
|
|
|
343
339
|
let activeCollectionPath = '';
|
|
344
340
|
let activeEditId = null;
|
|
345
341
|
|
|
346
|
-
// Group discovery metadata into unified conceptual resource targets
|
|
347
342
|
function resolveRoutes() {
|
|
348
343
|
Object.values(ENDPOINTS).forEach(ep => {
|
|
349
|
-
// Identify root paths that are collection containers (e.g., /api/v1/products, /api/v1/users)
|
|
350
344
|
if (!ep.path.includes(':')) {
|
|
351
345
|
if (!dynamicCollections[ep.path]) {
|
|
352
346
|
dynamicCollections[ep.path] = { get: null, post: null, put: null, del: null, modelFields: ep.fields || [] };
|
|
@@ -357,7 +351,6 @@ const UI = {
|
|
|
357
351
|
if (ep.fields && ep.fields.length) dynamicCollections[ep.path].modelFields = ep.fields;
|
|
358
352
|
}
|
|
359
353
|
} else {
|
|
360
|
-
// Match corresponding parameterized items to complete the sub-resource route setup (e.g., /api/v1/products/:id)
|
|
361
354
|
const basePath = ep.path.split('/:')[0];
|
|
362
355
|
if (!dynamicCollections[basePath]) {
|
|
363
356
|
dynamicCollections[basePath] = { get: null, post: null, put: null, del: null, modelFields: [] };
|
|
@@ -367,7 +360,6 @@ const UI = {
|
|
|
367
360
|
}
|
|
368
361
|
});
|
|
369
362
|
|
|
370
|
-
// Clean out incomplete route profiles from selector options
|
|
371
363
|
const selector = document.getElementById('route-selector');
|
|
372
364
|
Object.keys(dynamicCollections).forEach(path => {
|
|
373
365
|
if (dynamicCollections[path].get) {
|
|
@@ -397,7 +389,7 @@ const UI = {
|
|
|
397
389
|
const fields = dynamicCollections[activeCollectionPath].modelFields;
|
|
398
390
|
|
|
399
391
|
if (!fields || fields.length === 0) {
|
|
400
|
-
container.innerHTML = '<p style="font-size:12px; color:var(--text-dim);">No input properties found
|
|
392
|
+
container.innerHTML = '<p style="font-size:12px; color:var(--text-dim);">No input properties found.</p>';
|
|
401
393
|
return;
|
|
402
394
|
}
|
|
403
395
|
|
|
@@ -415,16 +407,17 @@ const UI = {
|
|
|
415
407
|
const head = document.getElementById('table-head');
|
|
416
408
|
const body = document.getElementById('table-body');
|
|
417
409
|
head.innerHTML = '';
|
|
418
|
-
body.innerHTML = '<tr><td style="padding:20px; color:var(--text-dim)">Loading
|
|
410
|
+
body.innerHTML = '<tr><td style="padding:20px; color:var(--text-dim)">Loading layout schemas...</td></tr>';
|
|
419
411
|
|
|
420
412
|
try {
|
|
421
413
|
const res = await fetch(activeCollectionPath, { headers: { 'Authorization': 'Bearer ' + token } });
|
|
422
414
|
const rawData = await res.json();
|
|
423
415
|
|
|
424
|
-
// Flatten standard array wrapping logic safely
|
|
425
416
|
let list = [];
|
|
426
|
-
if (Array.isArray(rawData))
|
|
427
|
-
|
|
417
|
+
if (Array.isArray(rawData)) {
|
|
418
|
+
list = rawData;
|
|
419
|
+
} else if (rawData && typeof rawData === 'object') {
|
|
420
|
+
// UNIFIED RESPONSE FLATTENER: Extracts arrays even if nested inside object counts
|
|
428
421
|
const arrayKey = Object.keys(rawData).find(k => Array.isArray(rawData[k]));
|
|
429
422
|
list = arrayKey ? rawData[arrayKey] : [rawData];
|
|
430
423
|
}
|
|
@@ -434,16 +427,13 @@ const UI = {
|
|
|
434
427
|
return;
|
|
435
428
|
}
|
|
436
429
|
|
|
437
|
-
// Gather unique keys from database entities dynamically
|
|
438
430
|
let keys = Object.keys(list[0]).filter(k => typeof list[0][k] !== 'object');
|
|
439
431
|
|
|
440
|
-
// Generate headers
|
|
441
432
|
let trHead = '<tr>';
|
|
442
433
|
keys.forEach(k => trHead += \`<th>\${k}</th>\`);
|
|
443
434
|
trHead += '<th style="text-align:right; padding-right:20px;">Actions</th></tr>';
|
|
444
435
|
head.innerHTML = trHead;
|
|
445
436
|
|
|
446
|
-
// Populate row fields
|
|
447
437
|
body.innerHTML = '';
|
|
448
438
|
list.forEach(row => {
|
|
449
439
|
let trBody = '<tr>';
|
|
@@ -496,7 +486,7 @@ const UI = {
|
|
|
496
486
|
body: JSON.stringify(payload)
|
|
497
487
|
});
|
|
498
488
|
|
|
499
|
-
if (res.ok) { resetDataForm(); fetchData(); } else { alert('Submission declined
|
|
489
|
+
if (res.ok) { resetDataForm(); fetchData(); } else { alert('Submission declined.'); }
|
|
500
490
|
}
|
|
501
491
|
|
|
502
492
|
async function deleteRow(id) {
|
|
@@ -506,7 +496,7 @@ const UI = {
|
|
|
506
496
|
const url = delTemplate.replace(\`:\${paramName}\`, id);
|
|
507
497
|
|
|
508
498
|
const res = await fetch(url, { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token } });
|
|
509
|
-
if (res.ok) fetchData(); else alert('Delete request blocked
|
|
499
|
+
if (res.ok) fetchData(); else alert('Delete request blocked.');
|
|
510
500
|
}
|
|
511
501
|
|
|
512
502
|
function startRowEdit(id, encodedJson) {
|