dbviewer 0.5.3 → 0.5.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 +4 -4
- data/app/views/dbviewer/entity_relationship_diagrams/index.html.erb +95 -121
- data/lib/dbviewer/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d0b4fd21e1b0a48e17e9301cc629947f80a40e66b4e3f2120848eaffd50fa53
|
4
|
+
data.tar.gz: ab3fc815ced156f36e0640334c2ed304fd7c77b8c2b50d780b7c1a2d95ce2fd8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 658597f5db20651fd6fbd40078adfe9b7dec956a2c1933b87e76523a0f33bca278fbcbf02f5c822f92202419bb0c80ec4b9af6b24f9e0a02ea092bed4894b7e0
|
7
|
+
data.tar.gz: 96fe5ec2d5f105fd6f041fb393092f39012b8708dcf18f915c2b2fe606e587280d286b766a1f211e01f40f7ed8a3be616826782bede4e28a676ee49b16146e75
|
@@ -33,12 +33,35 @@
|
|
33
33
|
<div class="card-body p-0">
|
34
34
|
<div id="erd-container" class="w-100 h-100" style="min-height: 450px;">
|
35
35
|
<div id="erd-loading" class="d-flex justify-content-center align-items-center h-100" style="min-height: 450px;">
|
36
|
-
<div class="text-center">
|
37
|
-
<div class="
|
38
|
-
<
|
36
|
+
<div class="text-center" style="width: 100%; max-width: 500px;">
|
37
|
+
<div class="mb-4">
|
38
|
+
<i class="bi bi-diagram-3 text-primary" style="font-size: 3rem;"></i>
|
39
39
|
</div>
|
40
|
-
<
|
41
|
-
<
|
40
|
+
<h5 class="mb-3">Generating Entity Relationship Diagram</h5>
|
41
|
+
<p id="loading-phase" class="mb-3">Initializing...</p>
|
42
|
+
|
43
|
+
<!-- Progress bar for table loading -->
|
44
|
+
<div class="progress mb-3" style="height: 8px;">
|
45
|
+
<div id="table-progress-bar" class="progress-bar bg-primary" role="progressbar"
|
46
|
+
style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
|
47
|
+
</div>
|
48
|
+
</div>
|
49
|
+
|
50
|
+
<!-- Progress text -->
|
51
|
+
<div class="d-flex justify-content-between align-items-center mb-2">
|
52
|
+
<small class="text-muted">Table Details</small>
|
53
|
+
<small id="table-progress-text" class="text-muted">0 / 0</small>
|
54
|
+
</div>
|
55
|
+
|
56
|
+
<!-- Relationships loading indicator -->
|
57
|
+
<div id="relationships-status" class="d-flex align-items-center justify-content-center mt-3">
|
58
|
+
<div class="spinner-border spinner-border-sm text-secondary me-2" role="status">
|
59
|
+
<span class="visually-hidden">Loading...</span>
|
60
|
+
</div>
|
61
|
+
<small class="text-muted">Loading relationships...</small>
|
62
|
+
</div>
|
63
|
+
|
64
|
+
<small class="text-muted d-block mt-3">This may take a moment for databases with many tables</small>
|
42
65
|
</div>
|
43
66
|
</div>
|
44
67
|
<!-- The ERD will be rendered here -->
|
@@ -175,11 +198,13 @@
|
|
175
198
|
console.log('Relationships loaded:', data);
|
176
199
|
relationships = data.relationships || [];
|
177
200
|
relationshipsLoaded = true;
|
201
|
+
updateRelationshipsStatus(true);
|
178
202
|
return relationships;
|
179
203
|
})
|
180
204
|
.catch(error => {
|
181
205
|
console.error('Error fetching relationships:', error);
|
182
206
|
relationshipsLoaded = true; // Mark as loaded even on error to prevent infinite loading
|
207
|
+
updateRelationshipsStatus(true);
|
183
208
|
return [];
|
184
209
|
});
|
185
210
|
}
|
@@ -187,9 +212,48 @@
|
|
187
212
|
// Function to update loading status
|
188
213
|
function updateLoadingStatus(message) {
|
189
214
|
const loadingElement = document.getElementById('erd-loading');
|
190
|
-
const
|
191
|
-
if (
|
192
|
-
|
215
|
+
const loadingPhase = document.getElementById('loading-phase');
|
216
|
+
if (loadingPhase) {
|
217
|
+
loadingPhase.textContent = message;
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
// Function to update table loading progress
|
222
|
+
function updateTableProgress(loaded, total) {
|
223
|
+
const progressBar = document.getElementById('table-progress-bar');
|
224
|
+
const progressText = document.getElementById('table-progress-text');
|
225
|
+
|
226
|
+
if (progressBar && progressText) {
|
227
|
+
const percentage = total > 0 ? Math.round((loaded / total) * 100) : 0;
|
228
|
+
progressBar.style.width = percentage + '%';
|
229
|
+
progressBar.setAttribute('aria-valuenow', percentage);
|
230
|
+
progressText.textContent = `${loaded} / ${total}`;
|
231
|
+
|
232
|
+
// Update progress bar color based on completion
|
233
|
+
if (percentage === 100) {
|
234
|
+
progressBar.classList.remove('bg-primary');
|
235
|
+
progressBar.classList.add('bg-success');
|
236
|
+
}
|
237
|
+
}
|
238
|
+
}
|
239
|
+
|
240
|
+
// Function to update relationships status
|
241
|
+
function updateRelationshipsStatus(loaded) {
|
242
|
+
const relationshipsStatus = document.getElementById('relationships-status');
|
243
|
+
if (relationshipsStatus) {
|
244
|
+
if (loaded) {
|
245
|
+
relationshipsStatus.innerHTML = `
|
246
|
+
<i class="bi bi-check-circle text-success me-2"></i>
|
247
|
+
<small class="text-success">Relationships loaded</small>
|
248
|
+
`;
|
249
|
+
} else {
|
250
|
+
relationshipsStatus.innerHTML = `
|
251
|
+
<div class="spinner-border spinner-border-sm text-secondary me-2" role="status">
|
252
|
+
<span class="visually-hidden">Loading...</span>
|
253
|
+
</div>
|
254
|
+
<small class="text-muted">Loading relationships...</small>
|
255
|
+
`;
|
256
|
+
}
|
193
257
|
}
|
194
258
|
}
|
195
259
|
|
@@ -203,8 +267,12 @@
|
|
203
267
|
let columnsLoadedCount = 0;
|
204
268
|
const totalTables = tables.length;
|
205
269
|
|
270
|
+
// Initialize progress bar
|
271
|
+
updateTableProgress(0, totalTables);
|
272
|
+
updateLoadingStatus('Loading table details...');
|
273
|
+
|
206
274
|
// Start fetching relationships immediately
|
207
|
-
|
275
|
+
updateRelationshipsStatus(false);
|
208
276
|
const relationshipsPromise = fetchRelationships();
|
209
277
|
|
210
278
|
// First pass: add all tables with minimal info and start loading columns
|
@@ -227,8 +295,8 @@
|
|
227
295
|
tableColumns[tableName] = data.columns;
|
228
296
|
columnsLoadedCount++;
|
229
297
|
|
230
|
-
// Update
|
231
|
-
|
298
|
+
// Update progress bar
|
299
|
+
updateTableProgress(columnsLoadedCount, totalTables);
|
232
300
|
|
233
301
|
checkIfReadyToUpdate();
|
234
302
|
}
|
@@ -236,6 +304,7 @@
|
|
236
304
|
.catch(error => {
|
237
305
|
console.error(`Error fetching columns for table ${tableName}:`, error);
|
238
306
|
columnsLoadedCount++;
|
307
|
+
updateTableProgress(columnsLoadedCount, totalTables);
|
239
308
|
checkIfReadyToUpdate();
|
240
309
|
});
|
241
310
|
});
|
@@ -261,9 +330,9 @@
|
|
261
330
|
if (isUpdatingDiagram) return;
|
262
331
|
|
263
332
|
isUpdatingDiagram = true;
|
264
|
-
console.log('
|
333
|
+
console.log('Rendering diagram with full column and relationship data');
|
265
334
|
|
266
|
-
updateLoadingStatus('Generating diagram...');
|
335
|
+
updateLoadingStatus('Generating final diagram...');
|
267
336
|
|
268
337
|
// Regenerate the diagram with complete data
|
269
338
|
let updatedDefinition = 'erDiagram\n';
|
@@ -289,43 +358,33 @@
|
|
289
358
|
updatedDefinition += ' %% No relationships found in the database schema\n';
|
290
359
|
}
|
291
360
|
|
292
|
-
// Create
|
293
|
-
const
|
294
|
-
|
295
|
-
|
361
|
+
// Create the diagram element
|
362
|
+
const erdDiv = document.createElement('div');
|
363
|
+
erdDiv.className = 'mermaid';
|
364
|
+
erdDiv.innerHTML = updatedDefinition;
|
296
365
|
|
297
|
-
//
|
298
|
-
const container = document.getElementById('erd-container');
|
299
|
-
|
300
|
-
// First, clean up any previous zoom instance
|
301
|
-
if (panZoomInstance) {
|
302
|
-
panZoomInstance.destroy();
|
303
|
-
panZoomInstance = null;
|
304
|
-
}
|
305
|
-
|
306
|
-
// Create a temporary container
|
366
|
+
// Create a temporary container for rendering
|
307
367
|
const tempContainer = document.createElement('div');
|
308
368
|
tempContainer.style.visibility = 'hidden';
|
309
369
|
tempContainer.style.position = 'absolute';
|
310
370
|
tempContainer.style.width = '100%';
|
311
|
-
tempContainer.appendChild(
|
371
|
+
tempContainer.appendChild(erdDiv);
|
312
372
|
document.body.appendChild(tempContainer);
|
313
373
|
|
314
|
-
// Render in the temporary container
|
315
|
-
mermaid.init(undefined,
|
316
|
-
console.log('Diagram fully
|
374
|
+
// Render the diagram in the temporary container
|
375
|
+
mermaid.init(undefined, erdDiv).then(function() {
|
376
|
+
console.log('Diagram fully rendered with all data');
|
317
377
|
|
318
|
-
// Clear original container and move the rendered content
|
319
378
|
try {
|
320
379
|
// Remove from temp container without destroying
|
321
|
-
tempContainer.removeChild(
|
380
|
+
tempContainer.removeChild(erdDiv);
|
322
381
|
|
323
382
|
// Hide loading indicator
|
324
383
|
document.getElementById('erd-loading').style.display = 'none';
|
325
384
|
|
326
385
|
// Clear main container and add the diagram
|
327
386
|
container.innerHTML = '';
|
328
|
-
container.appendChild(
|
387
|
+
container.appendChild(erdDiv);
|
329
388
|
|
330
389
|
// Remove temp container
|
331
390
|
document.body.removeChild(tempContainer);
|
@@ -342,101 +401,16 @@
|
|
342
401
|
isUpdatingDiagram = false;
|
343
402
|
}
|
344
403
|
}).catch(function(error) {
|
345
|
-
console.error('Error rendering
|
404
|
+
console.error('Error rendering diagram:', error);
|
346
405
|
document.body.removeChild(tempContainer);
|
347
406
|
isUpdatingDiagram = false;
|
348
|
-
showError('Error rendering diagram', 'There was an error
|
407
|
+
showError('Error rendering diagram', 'There was an error rendering the entity relationship diagram.', error.message);
|
349
408
|
});
|
350
409
|
}
|
351
410
|
|
352
|
-
// Add initial relationships placeholder (empty)
|
353
|
-
mermaidDefinition += ' %% Relationships loading...\n';
|
354
|
-
|
355
|
-
// Create a div for the initial diagram (shows immediately with table names only)
|
356
|
-
const erdDiv = document.createElement('div');
|
357
|
-
erdDiv.className = 'mermaid';
|
358
|
-
erdDiv.innerHTML = mermaidDefinition;
|
359
|
-
|
360
411
|
// Get the container reference for later use
|
361
412
|
const container = document.getElementById('erd-container');
|
362
413
|
|
363
|
-
// Create a temporary container for initial rendering
|
364
|
-
const tempInitContainer = document.createElement('div');
|
365
|
-
tempInitContainer.style.visibility = 'hidden';
|
366
|
-
tempInitContainer.style.position = 'absolute';
|
367
|
-
tempInitContainer.style.width = '100%';
|
368
|
-
tempInitContainer.appendChild(erdDiv);
|
369
|
-
document.body.appendChild(tempInitContainer);
|
370
|
-
|
371
|
-
// Update loading status for initial render
|
372
|
-
updateLoadingStatus('Rendering initial diagram...');
|
373
|
-
|
374
|
-
// Render the initial diagram in the temporary container
|
375
|
-
mermaid.init(undefined, erdDiv).then(function() {
|
376
|
-
try {
|
377
|
-
// Remove from temp container without destroying
|
378
|
-
tempInitContainer.removeChild(erdDiv);
|
379
|
-
|
380
|
-
// Hide the loading indicator temporarily (will show updated loading for data fetching)
|
381
|
-
document.getElementById('erd-loading').style.display = 'none';
|
382
|
-
|
383
|
-
// Add the rendered diagram to the main container
|
384
|
-
container.appendChild(erdDiv);
|
385
|
-
|
386
|
-
// Remove temp container
|
387
|
-
document.body.removeChild(tempInitContainer);
|
388
|
-
|
389
|
-
// Setup initial zoom controls
|
390
|
-
setTimeout(() => {
|
391
|
-
setupZoomControls();
|
392
|
-
// Show a subtle loading indicator that data is still loading
|
393
|
-
showDataLoadingIndicator();
|
394
|
-
}, 100);
|
395
|
-
} catch(err) {
|
396
|
-
console.error('Error moving initial diagram to container:', err);
|
397
|
-
}
|
398
|
-
}).catch(function(error) {
|
399
|
-
console.error('Error rendering initial diagram:', error);
|
400
|
-
document.body.removeChild(tempInitContainer);
|
401
|
-
showError('Error generating diagram', 'There was an error generating the initial entity relationship diagram.', error.message);
|
402
|
-
});
|
403
|
-
|
404
|
-
// Function to show a subtle loading indicator for data loading
|
405
|
-
function showDataLoadingIndicator() {
|
406
|
-
// Create a small loading badge in the top-right corner
|
407
|
-
const loadingBadge = document.createElement('div');
|
408
|
-
loadingBadge.id = 'data-loading-badge';
|
409
|
-
loadingBadge.className = 'position-absolute top-0 end-0 m-3';
|
410
|
-
loadingBadge.style.zIndex = '1000';
|
411
|
-
loadingBadge.innerHTML = `
|
412
|
-
<div class="badge bg-info d-flex align-items-center">
|
413
|
-
<div class="spinner-border spinner-border-sm me-2" role="status" style="width: 0.8rem; height: 0.8rem;">
|
414
|
-
<span class="visually-hidden">Loading...</span>
|
415
|
-
</div>
|
416
|
-
Loading details...
|
417
|
-
</div>
|
418
|
-
`;
|
419
|
-
|
420
|
-
container.style.position = 'relative';
|
421
|
-
container.appendChild(loadingBadge);
|
422
|
-
|
423
|
-
// Remove the badge when data loading is complete
|
424
|
-
const checkComplete = () => {
|
425
|
-
if (columnsLoadedCount === totalTables && relationshipsLoaded) {
|
426
|
-
setTimeout(() => {
|
427
|
-
const badge = document.getElementById('data-loading-badge');
|
428
|
-
if (badge) {
|
429
|
-
badge.remove();
|
430
|
-
}
|
431
|
-
}, 500); // Small delay to show completion
|
432
|
-
} else {
|
433
|
-
setTimeout(checkComplete, 500);
|
434
|
-
}
|
435
|
-
};
|
436
|
-
|
437
|
-
setTimeout(checkComplete, 1000);
|
438
|
-
}
|
439
|
-
|
440
414
|
// SVG Pan Zoom instance
|
441
415
|
let panZoomInstance = null;
|
442
416
|
|
data/lib/dbviewer/version.rb
CHANGED