dbviewer 0.6.7 → 0.7.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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/dbviewer/entity_relationship_diagram.js +553 -0
- data/app/assets/javascripts/dbviewer/home.js +287 -0
- data/app/assets/javascripts/dbviewer/layout.js +194 -0
- data/app/assets/javascripts/dbviewer/query.js +277 -0
- data/app/assets/javascripts/dbviewer/table.js +1563 -0
- data/app/assets/stylesheets/dbviewer/application.css +1460 -21
- data/app/assets/stylesheets/dbviewer/entity_relationship_diagram.css +181 -0
- data/app/assets/stylesheets/dbviewer/home.css +229 -0
- data/app/assets/stylesheets/dbviewer/logs.css +64 -0
- data/app/assets/stylesheets/dbviewer/query.css +171 -0
- data/app/assets/stylesheets/dbviewer/table.css +1144 -0
- data/app/views/dbviewer/connections/index.html.erb +0 -30
- data/app/views/dbviewer/entity_relationship_diagrams/index.html.erb +14 -713
- data/app/views/dbviewer/home/index.html.erb +9 -499
- data/app/views/dbviewer/logs/index.html.erb +5 -220
- data/app/views/dbviewer/tables/index.html.erb +0 -65
- data/app/views/dbviewer/tables/query.html.erb +129 -565
- data/app/views/dbviewer/tables/show.html.erb +4 -2429
- data/app/views/layouts/dbviewer/application.html.erb +13 -1544
- data/lib/dbviewer/version.rb +1 -1
- metadata +12 -7
- data/app/assets/javascripts/dbviewer/connections.js +0 -70
- data/app/assets/stylesheets/dbviewer/dbviewer.css +0 -0
- data/app/assets/stylesheets/dbviewer/enhanced.css +0 -0
- data/app/views/dbviewer/connections/new.html.erb +0 -79
- data/app/views/dbviewer/tables/mini_erd.html.erb +0 -517
@@ -1,3 +1,8 @@
|
|
1
|
+
<% content_for :head do %>
|
2
|
+
<%= stylesheet_link_tag "dbviewer/home", "data-turbo-track": "reload" %>
|
3
|
+
<%= javascript_include_tag "dbviewer/home", "data-turbo-track": "reload" %>
|
4
|
+
<% end %>
|
5
|
+
|
1
6
|
<div class="container-fluid px-0">
|
2
7
|
<div class="row mb-3">
|
3
8
|
<div class="col">
|
@@ -131,502 +136,7 @@
|
|
131
136
|
</div>
|
132
137
|
</div>
|
133
138
|
|
134
|
-
<
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
139
|
-
}
|
140
|
-
|
141
|
-
// Helper function to format file sizes
|
142
|
-
function numberToHumanSize(bytes) {
|
143
|
-
if (bytes === null || bytes === undefined) return 'N/A';
|
144
|
-
if (bytes === 0) return '0 Bytes';
|
145
|
-
|
146
|
-
const k = 1024;
|
147
|
-
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
148
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
149
|
-
|
150
|
-
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
151
|
-
}
|
152
|
-
|
153
|
-
// Function to update analytics cards
|
154
|
-
function updateTablesCount(data) {
|
155
|
-
document.getElementById('tables-loading').classList.add('d-none');
|
156
|
-
document.getElementById('tables-count').classList.remove('d-none');
|
157
|
-
document.getElementById('tables-count').textContent = data.total_tables || 0;
|
158
|
-
}
|
159
|
-
|
160
|
-
function updateRelationshipsCount(data) {
|
161
|
-
document.getElementById('relationships-loading').classList.add('d-none');
|
162
|
-
document.getElementById('relationships-count').classList.remove('d-none');
|
163
|
-
document.getElementById('relationships-count').textContent = data.total_relationships || 0;
|
164
|
-
}
|
165
|
-
|
166
|
-
function updateDatabaseSize(data) {
|
167
|
-
document.getElementById('size-loading').classList.add('d-none');
|
168
|
-
document.getElementById('size-count').classList.remove('d-none');
|
169
|
-
document.getElementById('size-count').textContent = numberToHumanSize(data.schema_size);
|
170
|
-
}
|
171
|
-
|
172
|
-
function updateRecordsData(recordsData) {
|
173
|
-
// Update records count
|
174
|
-
document.getElementById('records-loading').classList.add('d-none');
|
175
|
-
document.getElementById('records-count').classList.remove('d-none');
|
176
|
-
document.getElementById('records-count').textContent = numberWithDelimiter(recordsData.total_records || 0);
|
177
|
-
|
178
|
-
// Update largest tables
|
179
|
-
updateLargestTables(recordsData);
|
180
|
-
}
|
181
|
-
|
182
|
-
// Function to update largest tables
|
183
|
-
function updateLargestTables(data) {
|
184
|
-
const container = document.getElementById('largest-tables-container');
|
185
|
-
|
186
|
-
if (data.largest_tables && data.largest_tables.length > 0) {
|
187
|
-
const tableHtml = `
|
188
|
-
<div class="table-responsive">
|
189
|
-
<table class="table table-sm table-hover">
|
190
|
-
<thead>
|
191
|
-
<tr>
|
192
|
-
<th>Table Name</th>
|
193
|
-
<th class="text-end">Records</th>
|
194
|
-
</tr>
|
195
|
-
</thead>
|
196
|
-
<tbody>
|
197
|
-
${data.largest_tables.map(table => `
|
198
|
-
<tr>
|
199
|
-
<td>
|
200
|
-
<a href="${window.location.origin}${window.location.pathname.replace(/\/$/, '')}/tables/${table.name}">
|
201
|
-
${table.name}
|
202
|
-
</a>
|
203
|
-
</td>
|
204
|
-
<td class="text-end">${numberWithDelimiter(table.record_count)}</td>
|
205
|
-
</tr>
|
206
|
-
`).join('')}
|
207
|
-
</tbody>
|
208
|
-
</table>
|
209
|
-
</div>
|
210
|
-
`;
|
211
|
-
container.innerHTML = tableHtml;
|
212
|
-
} else {
|
213
|
-
container.innerHTML = `
|
214
|
-
<div class="text-center my-4 empty-data-message">
|
215
|
-
<p>No table data available</p>
|
216
|
-
</div>
|
217
|
-
`;
|
218
|
-
}
|
219
|
-
}
|
220
|
-
|
221
|
-
// Function to update recent queries
|
222
|
-
function updateRecentQueries(data) {
|
223
|
-
const container = document.getElementById('recent-queries-container');
|
224
|
-
const linkContainer = document.getElementById('queries-view-all-link');
|
225
|
-
|
226
|
-
if (data.enabled) {
|
227
|
-
// Show "View All Logs" link if query logging is enabled
|
228
|
-
linkContainer.innerHTML = `
|
229
|
-
<a href="${window.location.origin}${window.location.pathname.replace(/\/$/, '')}/logs" class="btn btn-sm btn-primary">View All Logs</a>
|
230
|
-
`;
|
231
|
-
linkContainer.classList.remove('d-none');
|
232
|
-
|
233
|
-
if (data.queries && data.queries.length > 0) {
|
234
|
-
const tableHtml = `
|
235
|
-
<div class="table-responsive">
|
236
|
-
<table class="table table-sm table-hover mb-0">
|
237
|
-
<thead>
|
238
|
-
<tr>
|
239
|
-
<th>Query</th>
|
240
|
-
<th class="text-end" style="width: 120px">Duration</th>
|
241
|
-
<th class="text-end" style="width: 180px">Time</th>
|
242
|
-
</tr>
|
243
|
-
</thead>
|
244
|
-
<tbody>
|
245
|
-
${data.queries.map(query => {
|
246
|
-
const duration = query.duration_ms;
|
247
|
-
const durationClass = duration > 100 ? 'query-duration-slow' : 'query-duration';
|
248
|
-
const timestamp = new Date(query.timestamp);
|
249
|
-
const timeString = timestamp.toLocaleTimeString();
|
250
|
-
|
251
|
-
return `
|
252
|
-
<tr>
|
253
|
-
<td class="text-truncate" style="max-width: 500px;">
|
254
|
-
<code class="sql-query-code">${query.sql}</code>
|
255
|
-
</td>
|
256
|
-
<td class="text-end">
|
257
|
-
<span class="${durationClass}">
|
258
|
-
${duration} ms
|
259
|
-
</span>
|
260
|
-
</td>
|
261
|
-
<td class="text-end query-timestamp">
|
262
|
-
<small>${timeString}</small>
|
263
|
-
</td>
|
264
|
-
</tr>
|
265
|
-
`;
|
266
|
-
}).join('')}
|
267
|
-
</tbody>
|
268
|
-
</table>
|
269
|
-
</div>
|
270
|
-
`;
|
271
|
-
container.innerHTML = tableHtml;
|
272
|
-
} else {
|
273
|
-
container.innerHTML = `
|
274
|
-
<div class="text-center my-4 empty-data-message">
|
275
|
-
<p>No queries recorded yet</p>
|
276
|
-
</div>
|
277
|
-
`;
|
278
|
-
}
|
279
|
-
} else {
|
280
|
-
container.innerHTML = `
|
281
|
-
<div class="text-center my-4 empty-data-message">
|
282
|
-
<p>Query logging is disabled</p>
|
283
|
-
<small class="text-muted">Enable it in the configuration to see SQL queries here</small>
|
284
|
-
</div>
|
285
|
-
`;
|
286
|
-
}
|
287
|
-
}
|
288
|
-
|
289
|
-
// Function to show error state
|
290
|
-
function showError(containerId, message) {
|
291
|
-
const container = document.getElementById(containerId);
|
292
|
-
container.innerHTML = `
|
293
|
-
<div class="text-center my-4 text-danger">
|
294
|
-
<i class="bi bi-exclamation-triangle fs-2 d-block mb-2"></i>
|
295
|
-
<p>Error loading data</p>
|
296
|
-
<small>${message}</small>
|
297
|
-
</div>
|
298
|
-
`;
|
299
|
-
}
|
300
|
-
|
301
|
-
// Load tables count data
|
302
|
-
fetch('<%= dbviewer.api_tables_path %>', {
|
303
|
-
headers: {
|
304
|
-
'Accept': 'application/json',
|
305
|
-
'X-Requested-With': 'XMLHttpRequest'
|
306
|
-
}
|
307
|
-
})
|
308
|
-
.then(response => {
|
309
|
-
if (!response.ok) {
|
310
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
311
|
-
}
|
312
|
-
return response.json();
|
313
|
-
})
|
314
|
-
.then(data => {
|
315
|
-
updateTablesCount(data);
|
316
|
-
})
|
317
|
-
.catch(error => {
|
318
|
-
console.error('Error loading tables count:', error);
|
319
|
-
const loading = document.getElementById('tables-loading');
|
320
|
-
const count = document.getElementById('tables-count');
|
321
|
-
loading.classList.add('d-none');
|
322
|
-
count.classList.remove('d-none');
|
323
|
-
count.innerHTML = '<span class="text-danger">Error</span>';
|
324
|
-
});
|
325
|
-
|
326
|
-
// Load database size data
|
327
|
-
fetch('<%= dbviewer.size_api_database_path %>', {
|
328
|
-
headers: {
|
329
|
-
'Accept': 'application/json',
|
330
|
-
'X-Requested-With': 'XMLHttpRequest'
|
331
|
-
}
|
332
|
-
})
|
333
|
-
.then(response => {
|
334
|
-
if (!response.ok) {
|
335
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
336
|
-
}
|
337
|
-
return response.json();
|
338
|
-
})
|
339
|
-
.then(data => {
|
340
|
-
updateDatabaseSize(data);
|
341
|
-
})
|
342
|
-
.catch(error => {
|
343
|
-
console.error('Error loading database size:', error);
|
344
|
-
const loading = document.getElementById('size-loading');
|
345
|
-
const count = document.getElementById('size-count');
|
346
|
-
loading.classList.add('d-none');
|
347
|
-
count.classList.remove('d-none');
|
348
|
-
count.innerHTML = '<span class="text-danger">Error</span>';
|
349
|
-
});
|
350
|
-
|
351
|
-
// Load records data separately
|
352
|
-
fetch('<%= dbviewer.records_api_tables_path %>', {
|
353
|
-
headers: {
|
354
|
-
'Accept': 'application/json',
|
355
|
-
'X-Requested-With': 'XMLHttpRequest'
|
356
|
-
}
|
357
|
-
})
|
358
|
-
.then(response => {
|
359
|
-
if (!response.ok) {
|
360
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
361
|
-
}
|
362
|
-
return response.json();
|
363
|
-
})
|
364
|
-
.then(recordsData => {
|
365
|
-
updateRecordsData(recordsData);
|
366
|
-
})
|
367
|
-
.catch(error => {
|
368
|
-
console.error('Error loading records data:', error);
|
369
|
-
// Update records-related UI with error state
|
370
|
-
const recordsLoading = document.getElementById('records-loading');
|
371
|
-
const recordsCount = document.getElementById('records-count');
|
372
|
-
recordsLoading.classList.add('d-none');
|
373
|
-
recordsCount.classList.remove('d-none');
|
374
|
-
recordsCount.innerHTML = '<span class="text-danger">Error</span>';
|
375
|
-
|
376
|
-
showError('largest-tables-container', error.message);
|
377
|
-
});
|
378
|
-
|
379
|
-
// Load recent queries data
|
380
|
-
fetch('<%= dbviewer.recent_api_queries_path %>', {
|
381
|
-
headers: {
|
382
|
-
'Accept': 'application/json',
|
383
|
-
'X-Requested-With': 'XMLHttpRequest'
|
384
|
-
}
|
385
|
-
})
|
386
|
-
.then(response => {
|
387
|
-
if (!response.ok) {
|
388
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
389
|
-
}
|
390
|
-
return response.json();
|
391
|
-
})
|
392
|
-
.then(data => {
|
393
|
-
updateRecentQueries(data);
|
394
|
-
})
|
395
|
-
.catch(error => {
|
396
|
-
console.error('Error loading recent queries:', error);
|
397
|
-
showError('recent-queries-container', error.message);
|
398
|
-
});
|
399
|
-
});
|
400
|
-
</script>
|
401
|
-
|
402
|
-
<style>
|
403
|
-
/* ================================================
|
404
|
-
CSS Custom Properties (CSS Variables)
|
405
|
-
================================================ */
|
406
|
-
:root {
|
407
|
-
/* Colors */
|
408
|
-
--dbviewer-code-bg: rgba(0, 0, 0, 0.05);
|
409
|
-
--dbviewer-code-border: rgba(0, 0, 0, 0.1);
|
410
|
-
--dbviewer-muted-color: #6c757d;
|
411
|
-
--dbviewer-success-color: #28a745;
|
412
|
-
--dbviewer-danger-color: #dc3545;
|
413
|
-
--dbviewer-warning-color: #ffc107;
|
414
|
-
|
415
|
-
/* Skeleton loader colors */
|
416
|
-
--skeleton-base-color: #f0f0f0;
|
417
|
-
--skeleton-highlight-color: #e0e0e0;
|
418
|
-
|
419
|
-
/* Typography */
|
420
|
-
--dbviewer-monospace-font: 'Courier New', Courier, monospace;
|
421
|
-
--dbviewer-code-font-size: 0.85rem;
|
422
|
-
|
423
|
-
/* Spacing and sizing */
|
424
|
-
--dbviewer-border-radius: 4px;
|
425
|
-
--dbviewer-border-radius-sm: 3px;
|
426
|
-
--dbviewer-padding-sm: 2px 4px;
|
427
|
-
}
|
428
|
-
|
429
|
-
/* ================================================
|
430
|
-
Dark Mode Support
|
431
|
-
================================================ */
|
432
|
-
@media (prefers-color-scheme: dark) {
|
433
|
-
:root {
|
434
|
-
--dbviewer-code-bg: rgba(255, 255, 255, 0.1);
|
435
|
-
--dbviewer-code-border: rgba(255, 255, 255, 0.15);
|
436
|
-
--dbviewer-muted-color: #adb5bd;
|
437
|
-
--skeleton-base-color: #2a2a2a;
|
438
|
-
--skeleton-highlight-color: #404040;
|
439
|
-
}
|
440
|
-
}
|
441
|
-
|
442
|
-
/* Bootstrap dark mode support */
|
443
|
-
[data-bs-theme="dark"] {
|
444
|
-
--dbviewer-code-bg: rgba(255, 255, 255, 0.1);
|
445
|
-
--dbviewer-code-border: rgba(255, 255, 255, 0.15);
|
446
|
-
--dbviewer-muted-color: #adb5bd;
|
447
|
-
--skeleton-base-color: #2a2a2a;
|
448
|
-
--skeleton-highlight-color: #404040;
|
449
|
-
}
|
450
|
-
|
451
|
-
/* ================================================
|
452
|
-
SQL Query Styling
|
453
|
-
================================================ */
|
454
|
-
.sql-query-code {
|
455
|
-
font-family: var(--dbviewer-monospace-font);
|
456
|
-
font-size: var(--dbviewer-code-font-size);
|
457
|
-
background-color: var(--dbviewer-code-bg);
|
458
|
-
padding: var(--dbviewer-padding-sm);
|
459
|
-
border-radius: var(--dbviewer-border-radius-sm);
|
460
|
-
border: 1px solid var(--dbviewer-code-border);
|
461
|
-
transition: background-color 0.2s ease, border-color 0.2s ease;
|
462
|
-
}
|
463
|
-
|
464
|
-
.sql-query-code:hover {
|
465
|
-
background-color: var(--dbviewer-code-bg);
|
466
|
-
filter: brightness(0.95);
|
467
|
-
}
|
468
|
-
|
469
|
-
/* ================================================
|
470
|
-
Query Performance Indicators
|
471
|
-
================================================ */
|
472
|
-
.query-duration {
|
473
|
-
color: var(--dbviewer-success-color);
|
474
|
-
font-weight: 500;
|
475
|
-
font-variant-numeric: tabular-nums;
|
476
|
-
transition: color 0.2s ease;
|
477
|
-
}
|
478
|
-
|
479
|
-
.query-duration-slow {
|
480
|
-
color: var(--dbviewer-danger-color);
|
481
|
-
font-weight: 600;
|
482
|
-
font-variant-numeric: tabular-nums;
|
483
|
-
transition: color 0.2s ease;
|
484
|
-
}
|
485
|
-
|
486
|
-
.query-timestamp {
|
487
|
-
color: var(--dbviewer-muted-color);
|
488
|
-
font-variant-numeric: tabular-nums;
|
489
|
-
transition: color 0.2s ease;
|
490
|
-
}
|
491
|
-
|
492
|
-
/* ================================================
|
493
|
-
Empty States and Messages
|
494
|
-
================================================ */
|
495
|
-
.empty-data-message {
|
496
|
-
color: var(--dbviewer-muted-color);
|
497
|
-
transition: color 0.2s ease;
|
498
|
-
}
|
499
|
-
|
500
|
-
.empty-data-message p {
|
501
|
-
margin-bottom: 0.5rem;
|
502
|
-
font-weight: 500;
|
503
|
-
}
|
504
|
-
|
505
|
-
.empty-data-message small {
|
506
|
-
opacity: 0.8;
|
507
|
-
}
|
508
|
-
|
509
|
-
/* ================================================
|
510
|
-
Loading States
|
511
|
-
================================================ */
|
512
|
-
.spinner-border-sm {
|
513
|
-
width: 1rem;
|
514
|
-
height: 1rem;
|
515
|
-
}
|
516
|
-
|
517
|
-
/* ================================================
|
518
|
-
Skeleton Loader System
|
519
|
-
================================================ */
|
520
|
-
.skeleton-loader {
|
521
|
-
display: inline-block;
|
522
|
-
height: 1.2em;
|
523
|
-
width: 100%;
|
524
|
-
background: linear-gradient(
|
525
|
-
90deg,
|
526
|
-
var(--skeleton-base-color) 25%,
|
527
|
-
var(--skeleton-highlight-color) 37%,
|
528
|
-
var(--skeleton-base-color) 63%
|
529
|
-
);
|
530
|
-
background-size: 400% 100%;
|
531
|
-
animation: skeleton-loading 1.2s ease-in-out infinite;
|
532
|
-
border-radius: var(--dbviewer-border-radius);
|
533
|
-
}
|
534
|
-
|
535
|
-
/* Skeleton loader variants */
|
536
|
-
.skeleton-loader.number-loader {
|
537
|
-
width: 2.5em;
|
538
|
-
height: 1.5em;
|
539
|
-
margin-bottom: 0.2em;
|
540
|
-
}
|
541
|
-
|
542
|
-
.skeleton-loader.table-cell-loader {
|
543
|
-
width: 6em;
|
544
|
-
height: 1.2em;
|
545
|
-
}
|
546
|
-
|
547
|
-
.skeleton-loader.records-loader {
|
548
|
-
width: 3em;
|
549
|
-
height: 1.2em;
|
550
|
-
}
|
551
|
-
|
552
|
-
.skeleton-loader.query-cell-loader {
|
553
|
-
width: 12em;
|
554
|
-
height: 1.2em;
|
555
|
-
}
|
556
|
-
|
557
|
-
.skeleton-loader.duration-cell-loader {
|
558
|
-
width: 4em;
|
559
|
-
height: 1.2em;
|
560
|
-
}
|
561
|
-
|
562
|
-
.skeleton-loader.time-cell-loader {
|
563
|
-
width: 7em;
|
564
|
-
height: 1.2em;
|
565
|
-
}
|
566
|
-
|
567
|
-
/* ================================================
|
568
|
-
Animations
|
569
|
-
================================================ */
|
570
|
-
@keyframes skeleton-loading {
|
571
|
-
0% {
|
572
|
-
background-position: 100% 50%;
|
573
|
-
}
|
574
|
-
100% {
|
575
|
-
background-position: 0 50%;
|
576
|
-
}
|
577
|
-
}
|
578
|
-
|
579
|
-
/* ================================================
|
580
|
-
Table Enhancements
|
581
|
-
================================================ */
|
582
|
-
.table-hover tbody tr:hover .sql-query-code {
|
583
|
-
background-color: var(--dbviewer-code-bg);
|
584
|
-
filter: brightness(0.9);
|
585
|
-
}
|
586
|
-
|
587
|
-
/* ================================================
|
588
|
-
Responsive Design
|
589
|
-
================================================ */
|
590
|
-
@media (max-width: 768px) {
|
591
|
-
.sql-query-code {
|
592
|
-
font-size: 0.75rem;
|
593
|
-
padding: 1px 3px;
|
594
|
-
}
|
595
|
-
|
596
|
-
.query-cell-loader {
|
597
|
-
width: 8em;
|
598
|
-
}
|
599
|
-
|
600
|
-
.duration-cell-loader {
|
601
|
-
width: 3em;
|
602
|
-
}
|
603
|
-
|
604
|
-
.time-cell-loader {
|
605
|
-
width: 5em;
|
606
|
-
}
|
607
|
-
}
|
608
|
-
|
609
|
-
/* ================================================
|
610
|
-
Accessibility Improvements
|
611
|
-
================================================ */
|
612
|
-
@media (prefers-reduced-motion: reduce) {
|
613
|
-
.skeleton-loader {
|
614
|
-
animation: none;
|
615
|
-
background: var(--skeleton-base-color);
|
616
|
-
}
|
617
|
-
|
618
|
-
.sql-query-code,
|
619
|
-
.query-duration,
|
620
|
-
.query-duration-slow,
|
621
|
-
.query-timestamp,
|
622
|
-
.empty-data-message {
|
623
|
-
transition: none;
|
624
|
-
}
|
625
|
-
}
|
626
|
-
|
627
|
-
/* Focus states for better keyboard navigation */
|
628
|
-
.sql-query-code:focus-visible {
|
629
|
-
outline: 2px solid var(--dbviewer-success-color);
|
630
|
-
outline-offset: 2px;
|
631
|
-
}
|
632
|
-
</style>
|
139
|
+
<input type="text" id="recent_api_queries_path" class="d-none" value="<%= dbviewer.recent_api_queries_path %>">
|
140
|
+
<input type="text" id="api_tables_path" class="d-none" value="<%= dbviewer.api_tables_path %>">
|
141
|
+
<input type="text" id="size_api_database_path" class="d-none" value="<%= dbviewer.size_api_database_path %>">
|
142
|
+
<input type="text" id="records_api_tables_path" class="d-none" value="<%= dbviewer.records_api_tables_path %>">
|