dbviewer 0.4.3 → 0.4.4
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b726fcc60badaa82692f22151b9656152810ecaa9a5c59e39e0a27e0c595add5
|
4
|
+
data.tar.gz: a88f8817f599d276ad814bce26fa2314bd79c7c4a5979123aa524457c7c0d534
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0a0cfc7172bf1ea0e3146bfeb3cb739e247a8412c0fd204828fdb0e2a4f261fdbd75ef070da765c1a6cde0d1ae0bd60b842346c71512a547c9d05dd592930ae
|
7
|
+
data.tar.gz: 5304c49470fe85760bf0e6aef851cb3c199963be104518c46dad24dac6e22eaae597802786c339b9a779a810a8c849f9c1b558f73672abbb7f432429bbd9c519
|
@@ -6,10 +6,75 @@ module Dbviewer
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def analytics
|
9
|
-
|
9
|
+
# This method is deprecated but kept for backward compatibility
|
10
|
+
analytics_data = fetch_database_analytics
|
11
|
+
# Remove record data which will be served by the records endpoint
|
12
|
+
analytics_data.delete(:total_records)
|
13
|
+
analytics_data.delete(:largest_tables)
|
14
|
+
analytics_data.delete(:empty_tables)
|
15
|
+
analytics_data.delete(:avg_records_per_table)
|
10
16
|
|
11
17
|
respond_to do |format|
|
12
|
-
format.json { render json:
|
18
|
+
format.json { render json: analytics_data }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def tables_count
|
23
|
+
tables = fetch_tables_with_stats(include_record_counts: false)
|
24
|
+
|
25
|
+
respond_to do |format|
|
26
|
+
format.json { render json: { total_tables: tables.size } }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def relationships_count
|
31
|
+
begin
|
32
|
+
tables = fetch_tables_with_stats(include_record_counts: false)
|
33
|
+
total_relationships = 0
|
34
|
+
|
35
|
+
tables.each do |table|
|
36
|
+
metadata = fetch_table_metadata(table[:name])
|
37
|
+
total_relationships += metadata[:foreign_keys].size if metadata && metadata[:foreign_keys]
|
38
|
+
end
|
39
|
+
|
40
|
+
respond_to do |format|
|
41
|
+
format.json { render json: { total_relationships: total_relationships } }
|
42
|
+
end
|
43
|
+
rescue => e
|
44
|
+
Rails.logger.error("Error calculating relationship count: #{e.message}")
|
45
|
+
respond_to do |format|
|
46
|
+
format.json { render json: { total_relationships: 0, error: e.message }, status: :internal_server_error }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def database_size
|
52
|
+
begin
|
53
|
+
size = calculate_schema_size
|
54
|
+
|
55
|
+
respond_to do |format|
|
56
|
+
format.json { render json: { schema_size: size } }
|
57
|
+
end
|
58
|
+
rescue => e
|
59
|
+
Rails.logger.error("Error calculating schema size: #{e.message}")
|
60
|
+
respond_to do |format|
|
61
|
+
format.json { render json: { schema_size: nil, error: e.message }, status: :internal_server_error }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def records
|
67
|
+
tables = fetch_tables_with_stats(include_record_counts: true)
|
68
|
+
|
69
|
+
records_data = {
|
70
|
+
total_records: tables.sum { |t| t[:record_count] },
|
71
|
+
largest_tables: tables.sort_by { |t| -t[:record_count] }.first(10),
|
72
|
+
empty_tables: tables.select { |t| t[:record_count] == 0 },
|
73
|
+
avg_records_per_table: tables.any? ? (tables.sum { |t| t[:record_count] }.to_f / tables.size).round(1) : 0
|
74
|
+
}
|
75
|
+
|
76
|
+
respond_to do |format|
|
77
|
+
format.json { render json: records_data }
|
13
78
|
end
|
14
79
|
end
|
15
80
|
|
@@ -9,7 +9,7 @@
|
|
9
9
|
</div>
|
10
10
|
|
11
11
|
<div class="row g-3 mb-4" id="analytics-cards">
|
12
|
-
<div class="col-md-
|
12
|
+
<div class="col-md-4">
|
13
13
|
<div class="card h-100 border-0 shadow-sm <%= stat_card_bg_class %>">
|
14
14
|
<div class="card-body d-flex align-items-center">
|
15
15
|
<div class="metric-icon me-3">
|
@@ -28,7 +28,7 @@
|
|
28
28
|
</div>
|
29
29
|
</div>
|
30
30
|
|
31
|
-
<div class="col-md-
|
31
|
+
<div class="col-md-4">
|
32
32
|
<div class="card h-100 border-0 shadow-sm <%= stat_card_bg_class %>">
|
33
33
|
<div class="card-body d-flex align-items-center">
|
34
34
|
<div class="metric-icon me-3">
|
@@ -47,27 +47,7 @@
|
|
47
47
|
</div>
|
48
48
|
</div>
|
49
49
|
|
50
|
-
<div class="col-md-
|
51
|
-
<div class="card h-100 border-0 shadow-sm <%= stat_card_bg_class %>">
|
52
|
-
<div class="card-body d-flex align-items-center">
|
53
|
-
<div class="metric-icon me-3">
|
54
|
-
<i class="bi bi-link-45deg fs-4"></i>
|
55
|
-
</div>
|
56
|
-
<div class="text-start">
|
57
|
-
<h5 class="mb-1">Relationships</h5>
|
58
|
-
<h2 class="mb-0">
|
59
|
-
<span class="skeleton-loader number-loader" id="relationships-loading">
|
60
|
-
|
61
|
-
</span>
|
62
|
-
<span id="relationships-count" class="d-none">0</span>
|
63
|
-
</h2>
|
64
|
-
<small class="text-muted d-block">Foreign Key Connections</small>
|
65
|
-
</div>
|
66
|
-
</div>
|
67
|
-
</div>
|
68
|
-
</div>
|
69
|
-
|
70
|
-
<div class="col-md-3">
|
50
|
+
<div class="col-md-4">
|
71
51
|
<div class="card h-100 border-0 shadow-sm <%= stat_card_bg_class %>">
|
72
52
|
<div class="card-body d-flex align-items-center">
|
73
53
|
<div class="metric-icon me-3">
|
@@ -171,33 +151,39 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
171
151
|
}
|
172
152
|
|
173
153
|
// Function to update analytics cards
|
174
|
-
function
|
175
|
-
// Update tables count
|
154
|
+
function updateTablesCount(data) {
|
176
155
|
document.getElementById('tables-loading').classList.add('d-none');
|
177
156
|
document.getElementById('tables-count').classList.remove('d-none');
|
178
|
-
document.getElementById('tables-count').textContent =
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
document.getElementById('records-count').classList.remove('d-none');
|
183
|
-
document.getElementById('records-count').textContent = numberWithDelimiter(analytics.total_records || 0);
|
184
|
-
|
185
|
-
// Update relationships count
|
157
|
+
document.getElementById('tables-count').textContent = data.total_tables || 0;
|
158
|
+
}
|
159
|
+
|
160
|
+
function updateRelationshipsCount(data) {
|
186
161
|
document.getElementById('relationships-loading').classList.add('d-none');
|
187
162
|
document.getElementById('relationships-count').classList.remove('d-none');
|
188
|
-
document.getElementById('relationships-count').textContent =
|
189
|
-
|
190
|
-
|
163
|
+
document.getElementById('relationships-count').textContent = data.total_relationships || 0;
|
164
|
+
}
|
165
|
+
|
166
|
+
function updateDatabaseSize(data) {
|
191
167
|
document.getElementById('size-loading').classList.add('d-none');
|
192
168
|
document.getElementById('size-count').classList.remove('d-none');
|
193
|
-
document.getElementById('size-count').textContent = numberToHumanSize(
|
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);
|
194
180
|
}
|
195
181
|
|
196
182
|
// Function to update largest tables
|
197
|
-
function updateLargestTables(
|
183
|
+
function updateLargestTables(data) {
|
198
184
|
const container = document.getElementById('largest-tables-container');
|
199
185
|
|
200
|
-
if (
|
186
|
+
if (data.largest_tables && data.largest_tables.length > 0) {
|
201
187
|
const tableHtml = `
|
202
188
|
<div class="table-responsive">
|
203
189
|
<table class="table table-sm table-hover">
|
@@ -208,7 +194,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
208
194
|
</tr>
|
209
195
|
</thead>
|
210
196
|
<tbody>
|
211
|
-
${
|
197
|
+
${data.largest_tables.map(table => `
|
212
198
|
<tr>
|
213
199
|
<td>
|
214
200
|
<a href="${window.location.origin}${window.location.pathname.replace(/\/$/, '')}/tables/${table.name}">
|
@@ -312,8 +298,58 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
312
298
|
`;
|
313
299
|
}
|
314
300
|
|
315
|
-
// Load
|
316
|
-
fetch('<%=
|
301
|
+
// Load tables count data
|
302
|
+
fetch('<%= 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('<%= api_database_size_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('<%= api_records_path %>', {
|
317
353
|
headers: {
|
318
354
|
'Accept': 'application/json',
|
319
355
|
'X-Requested-With': 'XMLHttpRequest'
|
@@ -325,20 +361,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
325
361
|
}
|
326
362
|
return response.json();
|
327
363
|
})
|
328
|
-
.then(
|
329
|
-
|
330
|
-
updateLargestTables(analytics);
|
364
|
+
.then(recordsData => {
|
365
|
+
updateRecordsData(recordsData);
|
331
366
|
})
|
332
367
|
.catch(error => {
|
333
|
-
console.error('Error loading
|
334
|
-
// Update
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
count.innerHTML = '<span class="text-danger">Error</span>';
|
341
|
-
});
|
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>';
|
342
375
|
|
343
376
|
showError('largest-tables-container', error.message);
|
344
377
|
});
|
data/config/routes.rb
CHANGED
@@ -18,7 +18,13 @@ Dbviewer::Engine.routes.draw do
|
|
18
18
|
|
19
19
|
# Homepage and API endpoints
|
20
20
|
get "dashboard", to: "home#index", as: :dashboard
|
21
|
-
|
21
|
+
|
22
|
+
# Analytics API endpoints
|
23
|
+
get "api/analytics", to: "home#analytics" # Legacy/combined endpoint
|
24
|
+
get "api/records", to: "home#records"
|
25
|
+
get "api/tables", to: "home#tables_count"
|
26
|
+
get "api/relationships", to: "home#relationships_count"
|
27
|
+
get "api/database_size", to: "home#database_size"
|
22
28
|
get "api/recent_queries", to: "home#recent_queries"
|
23
29
|
|
24
30
|
root to: "home#index"
|
data/lib/dbviewer/version.rb
CHANGED