amaye15 commited on
Commit
2de1f9e
·
1 Parent(s): 9d7f38f

UI Improved

Browse files
Files changed (1) hide show
  1. index.html +198 -127
index.html CHANGED
@@ -382,17 +382,16 @@
382
  <div id="statusMessage"></div>
383
  </main>
384
  </div>
385
-
386
  <script>
387
- // --- Keep the existing element variables ---
388
  const tableList = document.getElementById('tableList');
389
  const schemaDisplay = document.getElementById('schemaDisplay');
390
  const schemaTable = document.getElementById('schemaTable');
391
- const schemaPlaceholder = document.getElementById('schemaPlaceholder'); // Added
392
  const dataDisplayContainer = document.getElementById('dataDisplayContainer');
393
  const dataDisplay = document.getElementById('dataDisplay');
394
  const dataTable = document.getElementById('dataTable');
395
- const dataPlaceholder = document.getElementById('dataPlaceholder'); // Added
396
  const tableDataHeader = document.getElementById('tableDataHeader');
397
  const sqlInput = document.getElementById('sqlInput');
398
  const runSqlButton = document.getElementById('runSqlButton');
@@ -402,16 +401,20 @@
402
  const statusMessage = document.getElementById('statusMessage');
403
  const loadingIndicator = document.getElementById('loadingIndicator');
404
 
405
- // --- API URL is relative ---
406
  const API_BASE_URL = '';
407
  let currentTables = [];
408
  let selectedTable = null;
 
409
  let pollingIntervalId = null;
410
- const POLLING_INTERVAL_MS = 1000; // Refresh table list every 10 seconds
411
 
412
- // --- Utility Functions (keep existing) ---
413
- function showLoader(show) {
414
- loadingIndicator.style.display = show ? 'inline-block' : 'none';
 
 
 
415
  }
416
 
417
  function showStatus(message, isError = false) {
@@ -426,8 +429,8 @@
426
  statusMessage.style.display = 'none';
427
  }
428
 
429
- async function fetchAPI(endpoint, options = {}) {
430
- showLoader(true);
431
  clearStatus();
432
  const url = `${API_BASE_URL}${endpoint}`;
433
  try {
@@ -440,25 +443,28 @@
440
  } catch (e) { /* Ignore */ }
441
  throw new Error(errorDetail);
442
  }
443
- // Check if the response is likely JSON before trying to parse
444
  const contentType = response.headers.get("content-type");
445
  if (contentType && contentType.includes("application/json")) {
446
  return await response.json();
447
  }
448
- // Assume text for non-JSON or if content-type is missing
449
  return await response.text();
450
  } catch (error) {
451
  console.error('API Fetch Error:', error);
452
- showStatus(`Error: ${error.message}`, true);
 
 
 
 
 
453
  throw error;
454
  } finally {
455
- showLoader(false);
456
  }
457
  }
458
 
459
  function renderTable(data, tableElement) {
460
  tableElement.innerHTML = '';
461
- if (!data || !Array.isArray(data)) { // Check if data is an array
462
  tableElement.innerHTML = '<tbody><tr><td>Invalid data format received.</td></tr></tbody>';
463
  console.error("Invalid data format for renderTable:", data);
464
  return;
@@ -486,17 +492,14 @@
486
  });
487
  }
488
 
489
- // --- renderSchema FIX ---
490
  function renderSchema(schemaData) {
491
- // Target the table directly
492
- schemaTable.innerHTML = ''; // Clear previous table content
493
- schemaPlaceholder.style.display = 'none'; // Hide placeholder
494
-
495
  if (!schemaData || !schemaData.columns || schemaData.columns.length === 0) {
496
  schemaTable.innerHTML = '<tbody><tr><td colspan="2">No schema information available.</td></tr></tbody>';
497
  return;
498
  }
499
-
500
  const thead = schemaTable.createTHead();
501
  const headerRow = thead.insertRow();
502
  ['Name', 'Type'].forEach(headerText => {
@@ -504,7 +507,6 @@
504
  th.textContent = headerText;
505
  headerRow.appendChild(th);
506
  });
507
-
508
  const tbody = schemaTable.createTBody();
509
  schemaData.columns.forEach(column => {
510
  const row = tbody.insertRow();
@@ -513,67 +515,52 @@
513
  });
514
  }
515
 
516
-
517
- // --- Event Handlers (Modified) ---
518
 
519
  async function loadTables(isPolling = false) {
520
  if (!isPolling) {
521
  tableList.innerHTML = '<li>Loading tables...</li>';
522
- schemaTable.innerHTML = '';
523
- dataTable.innerHTML = '';
524
- tableDataHeader.textContent = '';
525
- queryResultContainer.style.display = 'none';
526
- schemaPlaceholder.style.display = 'block'; // Show placeholders initially
527
- dataPlaceholder.style.display = 'block';
528
  }
529
  try {
530
- const newTables = await fetchAPI('/tables');
531
- // Check if the list actually changed before re-rendering
532
- if (!isPolling || JSON.stringify(newTables) !== JSON.stringify(currentTables)) {
533
  console.log("Table list changed, updating UI.");
534
  currentTables = newTables;
535
  displayTables(currentTables);
536
- if (!isPolling) {
537
- showStatus("Tables loaded.", false);
538
- }
539
- // If the currently selected table disappeared, clear the displays
540
  if (selectedTable && !currentTables.includes(selectedTable)) {
541
- console.log(`Selected table "${selectedTable}" removed.`);
542
- selectedTable = null;
543
- tableDataHeader.textContent = '';
544
- schemaDisplay.innerHTML = '<h4>Schema</h4><p id="schemaPlaceholder">Select a table from the list.</p><table id="schemaTable"></table>';
545
- dataDisplayContainer.innerHTML = '<h4>Data <span id="tableDataHeader"></span></h4><p id="dataPlaceholder">Select a table from the list.</p><div id="dataDisplay"><table id="dataTable"></table></div>';
546
- // Re-assign potentially overwritten elements
547
- schemaTable = document.getElementById('schemaTable');
548
- dataTable = document.getElementById('dataTable');
549
- schemaPlaceholder = document.getElementById('schemaPlaceholder');
550
- dataPlaceholder = document.getElementById('dataPlaceholder');
551
- tableDataHeader = document.getElementById('tableDataHeader');
552
- } else if (selectedTable && !isPolling) {
553
- // Optionally refresh current table view if needed,
554
- // but might be disruptive. Let's skip for now.
555
- // handleTableSelection(tableList.querySelector(`li[data-table-name="${selectedTable}"]`));
556
- }
557
- }
558
 
559
- // Clear placeholders if tables loaded successfully
560
- if (currentTables.length > 0 && !isPolling) {
561
- schemaPlaceholder.style.display = 'none';
562
- dataPlaceholder.style.display = 'none';
563
- } else if (currentTables.length === 0 && !isPolling) {
564
- tableList.innerHTML = '<li>No tables found.</li>';
565
  schemaPlaceholder.textContent = 'No tables found in the database.';
 
566
  dataPlaceholder.textContent = 'No tables found in the database.';
 
 
 
 
567
  }
568
 
569
  } catch (error) {
570
- if (!isPolling) { // Only show initial load error prominently
571
  tableList.innerHTML = '<li>Error loading tables.</li>';
572
  schemaPlaceholder.textContent = 'Error loading tables.';
 
573
  dataPlaceholder.textContent = 'Error loading tables.';
 
574
  } else {
575
- console.error("Polling error:", error); // Log polling errors quietly
576
  }
 
 
 
577
  }
578
  }
579
 
@@ -588,7 +575,6 @@
588
  li.textContent = tableName;
589
  li.dataset.tableName = tableName;
590
  li.onclick = () => handleTableSelection(li);
591
- // Re-apply active class if this table was selected
592
  if (tableName === selectedTable) {
593
  li.classList.add('active');
594
  }
@@ -596,7 +582,48 @@
596
  });
597
  }
598
 
599
- async function handleTableSelection(listItem) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
  const currentActive = tableList.querySelector('.active');
601
  if (currentActive) {
602
  currentActive.classList.remove('active');
@@ -604,75 +631,115 @@
604
  listItem.classList.add('active');
605
 
606
  selectedTable = listItem.dataset.tableName;
607
- if (!selectedTable) return;
608
-
609
- queryResultContainer.style.display = 'none';
610
- dataDisplayContainer.style.display = 'flex';
611
- dataPlaceholder.style.display = 'none'; // Hide placeholder
612
-
613
- tableDataHeader.textContent = `for table "${selectedTable}"`;
614
- schemaPlaceholder.style.display = 'none'; // Hide placeholder
615
- schemaTable.innerHTML = '<tbody><tr><td colspan="2">Loading schema...</td></tr></tbody>';
616
- dataTable.innerHTML = '<tbody><tr><td>Loading data...</td></tr></tbody>';
617
 
618
- try {
619
- const [schemaResponse, tableDataResponse] = await Promise.all([
620
- fetchAPI(`/tables/${selectedTable}/schema`),
621
- fetchAPI(`/tables/${selectedTable}?limit=100`)
622
- ]);
623
- renderSchema(schemaResponse);
624
- renderTable(tableDataResponse, dataTable);
625
- } catch (error) {
626
- schemaTable.innerHTML = '<tbody><tr><td colspan="2">Error loading schema.</td></tr></tbody>';
627
- dataTable.innerHTML = '<tbody><tr><td>Error loading data.</td></tr></tbody>';
628
- }
629
  }
630
 
631
-
632
- async function runCustomQuery() {
633
  const sql = sqlInput.value.trim();
634
  if (!sql) {
635
- showStatus("SQL query cannot be empty.", true);
636
  return;
637
  }
638
 
639
- // Clear active selection in sidebar if a custom query is run
640
- const currentActive = tableList.querySelector('.active');
641
- if (currentActive) {
642
- currentActive.classList.remove('active');
643
- }
644
- selectedTable = null; // Deselect table
645
-
646
- dataDisplayContainer.style.display = 'none';
647
- dataPlaceholder.style.display = 'none';
648
- schemaPlaceholder.style.display = 'block'; // Show placeholders again
649
- schemaTable.innerHTML = '';
650
- tableDataHeader.textContent = '';
651
-
652
- queryResultContainer.style.display = 'block';
653
- queryResultTable.innerHTML = '<tbody><tr><td>Running query...</td></tr></tbody>';
654
 
 
 
 
 
 
 
655
 
656
  try {
657
  const resultData = await fetchAPI('/query', {
658
  method: 'POST',
659
- headers: {
660
- 'Content-Type': 'application/json',
661
- },
662
  body: JSON.stringify({ sql: sql }),
663
- });
664
- renderTable(resultData, queryResultTable);
665
- showStatus("Query executed successfully.", false);
 
 
 
 
666
  } catch (error) {
667
- queryResultTable.innerHTML = '<tbody><tr><td>Error executing query. See status message.</td></tr></tbody>';
 
 
 
 
 
 
 
668
  }
669
  }
670
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
671
  // --- Polling Function ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
672
  function startPolling() {
673
- stopPolling(); // Clear existing interval if any
674
  console.log(`Starting polling every ${POLLING_INTERVAL_MS / 1000} seconds.`);
675
- pollingIntervalId = setInterval(() => loadTables(true), POLLING_INTERVAL_MS);
 
 
676
  }
677
 
678
  function stopPolling() {
@@ -684,28 +751,32 @@
684
  }
685
 
686
  // --- Initial Setup ---
687
- runSqlButton.onclick = runCustomQuery;
688
 
689
- // Load tables automatically when the page loads and start polling
690
  document.addEventListener('DOMContentLoaded', () => {
691
  loadTables().then(() => {
692
- // Start polling only after the initial load succeeds
693
- if (currentTables.length >= 0) { // Start even if no tables initially
694
  startPolling();
695
  }
696
  });
697
  });
698
 
699
- // Optional: Stop polling when the page is hidden (e.g., tab switched)
700
- // document.addEventListener("visibilitychange", () => {
701
- // if (document.visibilityState === 'hidden') {
702
- // stopPolling();
703
- // } else {
704
- // // Optionally restart polling immediately or wait for next interval
705
- // loadTables(); // Refresh immediately when tab becomes visible
706
- // startPolling();
707
- // }
708
- // });
 
 
 
 
 
 
709
 
710
  </script>
711
 
 
382
  <div id="statusMessage"></div>
383
  </main>
384
  </div>
 
385
  <script>
386
+ // --- Element Variables ---
387
  const tableList = document.getElementById('tableList');
388
  const schemaDisplay = document.getElementById('schemaDisplay');
389
  const schemaTable = document.getElementById('schemaTable');
390
+ const schemaPlaceholder = document.getElementById('schemaPlaceholder');
391
  const dataDisplayContainer = document.getElementById('dataDisplayContainer');
392
  const dataDisplay = document.getElementById('dataDisplay');
393
  const dataTable = document.getElementById('dataTable');
394
+ const dataPlaceholder = document.getElementById('dataPlaceholder');
395
  const tableDataHeader = document.getElementById('tableDataHeader');
396
  const sqlInput = document.getElementById('sqlInput');
397
  const runSqlButton = document.getElementById('runSqlButton');
 
401
  const statusMessage = document.getElementById('statusMessage');
402
  const loadingIndicator = document.getElementById('loadingIndicator');
403
 
404
+ // --- State Variables ---
405
  const API_BASE_URL = '';
406
  let currentTables = [];
407
  let selectedTable = null;
408
+ let currentCustomSQL = ''; // Keep track of the last run custom query
409
  let pollingIntervalId = null;
410
+ const POLLING_INTERVAL_MS = 5000; // Refresh every 5 seconds
411
 
412
+ // --- Utility Functions ---
413
+ function showLoader(show, isPolling = false) {
414
+ // Only show loader for non-polling actions
415
+ if (!isPolling) {
416
+ loadingIndicator.style.display = show ? 'inline-block' : 'none';
417
+ }
418
  }
419
 
420
  function showStatus(message, isError = false) {
 
429
  statusMessage.style.display = 'none';
430
  }
431
 
432
+ async function fetchAPI(endpoint, options = {}, isPolling = false) { // Pass isPolling flag
433
+ showLoader(true, isPolling); // Pass isPolling flag
434
  clearStatus();
435
  const url = `${API_BASE_URL}${endpoint}`;
436
  try {
 
443
  } catch (e) { /* Ignore */ }
444
  throw new Error(errorDetail);
445
  }
 
446
  const contentType = response.headers.get("content-type");
447
  if (contentType && contentType.includes("application/json")) {
448
  return await response.json();
449
  }
 
450
  return await response.text();
451
  } catch (error) {
452
  console.error('API Fetch Error:', error);
453
+ // Only show status for non-polling errors or make polling errors less prominent
454
+ if (!isPolling) {
455
+ showStatus(`Error: ${error.message}`, true);
456
+ } else {
457
+ console.warn(`Polling Error: ${error.message}`); // Log quietly
458
+ }
459
  throw error;
460
  } finally {
461
+ showLoader(false, isPolling); // Pass isPolling flag
462
  }
463
  }
464
 
465
  function renderTable(data, tableElement) {
466
  tableElement.innerHTML = '';
467
+ if (!data || !Array.isArray(data)) {
468
  tableElement.innerHTML = '<tbody><tr><td>Invalid data format received.</td></tr></tbody>';
469
  console.error("Invalid data format for renderTable:", data);
470
  return;
 
492
  });
493
  }
494
 
 
495
  function renderSchema(schemaData) {
496
+ schemaTable.innerHTML = '';
497
+ schemaPlaceholder.style.display = 'none';
 
 
498
  if (!schemaData || !schemaData.columns || schemaData.columns.length === 0) {
499
  schemaTable.innerHTML = '<tbody><tr><td colspan="2">No schema information available.</td></tr></tbody>';
500
  return;
501
  }
502
+ // schemaDisplay.innerHTML = '<h4>Schema</h4>'; // Header is already there
503
  const thead = schemaTable.createTHead();
504
  const headerRow = thead.insertRow();
505
  ['Name', 'Type'].forEach(headerText => {
 
507
  th.textContent = headerText;
508
  headerRow.appendChild(th);
509
  });
 
510
  const tbody = schemaTable.createTBody();
511
  schemaData.columns.forEach(column => {
512
  const row = tbody.insertRow();
 
515
  });
516
  }
517
 
518
+ // --- Core Logic Functions ---
 
519
 
520
  async function loadTables(isPolling = false) {
521
  if (!isPolling) {
522
  tableList.innerHTML = '<li>Loading tables...</li>';
523
+ resetDisplays();
 
 
 
 
 
524
  }
525
  try {
526
+ const newTables = await fetchAPI('/tables', {}, isPolling); // Pass polling flag
527
+ if (JSON.stringify(newTables) !== JSON.stringify(currentTables)) {
 
528
  console.log("Table list changed, updating UI.");
529
  currentTables = newTables;
530
  displayTables(currentTables);
531
+
532
+ // If the currently selected table disappeared, clear the displays
 
 
533
  if (selectedTable && !currentTables.includes(selectedTable)) {
534
+ console.log(`Selected table "${selectedTable}" removed.`);
535
+ resetToInitialState();
536
+ }
537
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
538
 
539
+ // Update placeholders based on current state
540
+ if (currentTables.length === 0 && !isPolling) {
541
+ tableList.innerHTML = '<li>No tables found.</li>';
 
 
 
542
  schemaPlaceholder.textContent = 'No tables found in the database.';
543
+ schemaPlaceholder.style.display = 'block';
544
  dataPlaceholder.textContent = 'No tables found in the database.';
545
+ dataPlaceholder.style.display = 'block';
546
+ } else if (currentTables.length > 0 && !selectedTable && !currentCustomSQL && !isPolling) {
547
+ schemaPlaceholder.style.display = 'block';
548
+ dataPlaceholder.style.display = 'block';
549
  }
550
 
551
  } catch (error) {
552
+ if (!isPolling) {
553
  tableList.innerHTML = '<li>Error loading tables.</li>';
554
  schemaPlaceholder.textContent = 'Error loading tables.';
555
+ schemaPlaceholder.style.display = 'block';
556
  dataPlaceholder.textContent = 'Error loading tables.';
557
+ dataPlaceholder.style.display = 'block';
558
  } else {
559
+ console.error("Polling error (loadTables):", error);
560
  }
561
+ // Stop polling on error to avoid spamming
562
+ stopPolling();
563
+ showStatus("Could not update table list. Polling stopped.", true);
564
  }
565
  }
566
 
 
575
  li.textContent = tableName;
576
  li.dataset.tableName = tableName;
577
  li.onclick = () => handleTableSelection(li);
 
578
  if (tableName === selectedTable) {
579
  li.classList.add('active');
580
  }
 
582
  });
583
  }
584
 
585
+ async function loadTableSchemaAndData(tableName, isPolling = false) {
586
+ if (!tableName) return;
587
+
588
+ // Only show placeholders/loading text on initial load, not polling refresh
589
+ if (!isPolling) {
590
+ dataDisplayContainer.style.display = 'flex';
591
+ queryResultContainer.style.display = 'none';
592
+ dataPlaceholder.style.display = 'none';
593
+ schemaPlaceholder.style.display = 'none';
594
+ tableDataHeader.textContent = `for table "${tableName}"`;
595
+ schemaTable.innerHTML = '<tbody><tr><td colspan="2">Loading schema...</td></tr></tbody>';
596
+ dataTable.innerHTML = '<tbody><tr><td>Loading data...</td></tr></tbody>';
597
+ }
598
+
599
+ try {
600
+ // Fetch concurrently
601
+ const [schemaResponse, tableDataResponse] = await Promise.all([
602
+ fetchAPI(`/tables/${tableName}/schema`, {}, isPolling), // Pass polling flag
603
+ fetchAPI(`/tables/${tableName}?limit=100`, {}, isPolling) // Pass polling flag
604
+ ]);
605
+ // Only render if the table is still the selected one (polling might finish after user clicks away)
606
+ if (selectedTable === tableName) {
607
+ renderSchema(schemaResponse);
608
+ renderTable(tableDataResponse, dataTable);
609
+ }
610
+ } catch (error) {
611
+ // Error shown by fetchAPI
612
+ // If the table disappeared during polling, loadTables will handle cleanup
613
+ if (selectedTable === tableName) { // Check if still selected
614
+ if (!isPolling) { // Don't overwrite placeholders if polling fails
615
+ schemaTable.innerHTML = '<tbody><tr><td colspan="2">Error loading schema.</td></tr></tbody>';
616
+ dataTable.innerHTML = '<tbody><tr><td>Error loading data.</td></tr></tbody>';
617
+ } else {
618
+ console.error(`Polling error for table ${tableName}:`, error);
619
+ // Optionally show a less intrusive error or just log it
620
+ // showStatus(`Could not refresh data for ${tableName}`, true);
621
+ }
622
+ }
623
+ }
624
+ }
625
+
626
+ function handleTableSelection(listItem) {
627
  const currentActive = tableList.querySelector('.active');
628
  if (currentActive) {
629
  currentActive.classList.remove('active');
 
631
  listItem.classList.add('active');
632
 
633
  selectedTable = listItem.dataset.tableName;
634
+ currentCustomSQL = ''; // Clear custom query when selecting a table
635
+ sqlInput.value = ''; // Clear the textarea
 
 
 
 
 
 
 
 
636
 
637
+ loadTableSchemaAndData(selectedTable, false); // Initial load, not polling
 
 
 
 
 
 
 
 
 
 
638
  }
639
 
640
+ async function runCustomQuery(isPolling = false) {
 
641
  const sql = sqlInput.value.trim();
642
  if (!sql) {
643
+ if (!isPolling) showStatus("SQL query cannot be empty.", true);
644
  return;
645
  }
646
 
647
+ // Only update UI text/visibility on explicit run, not polling refresh
648
+ if (!isPolling) {
649
+ // Clear active selection in sidebar
650
+ const currentActive = tableList.querySelector('.active');
651
+ if (currentActive) {
652
+ currentActive.classList.remove('active');
653
+ }
654
+ selectedTable = null; // Deselect table
 
 
 
 
 
 
 
655
 
656
+ resetDisplays();
657
+ dataDisplayContainer.style.display = 'none';
658
+ queryResultContainer.style.display = 'block';
659
+ queryResultTable.innerHTML = '<tbody><tr><td>Running query...</td></tr></tbody>';
660
+ currentCustomSQL = sql; // Store the ran query
661
+ }
662
 
663
  try {
664
  const resultData = await fetchAPI('/query', {
665
  method: 'POST',
666
+ headers: { 'Content-Type': 'application/json', },
 
 
667
  body: JSON.stringify({ sql: sql }),
668
+ }, isPolling); // Pass polling flag
669
+
670
+ // Only render if this is still the active custom query
671
+ if (currentCustomSQL === sql) {
672
+ renderTable(resultData, queryResultTable);
673
+ if (!isPolling) showStatus("Query executed successfully.", false);
674
+ }
675
  } catch (error) {
676
+ // Error shown by fetchAPI
677
+ if (currentCustomSQL === sql) { // Only update if still relevant
678
+ if (!isPolling) {
679
+ queryResultTable.innerHTML = '<tbody><tr><td>Error executing query. See status message.</td></tr></tbody>';
680
+ } else {
681
+ console.error(`Polling error for query "${sql}":`, error);
682
+ }
683
+ }
684
  }
685
  }
686
 
687
+ function resetDisplays() {
688
+ // Reset schema display
689
+ schemaDisplay.innerHTML = '<h4>Schema</h4><p id="schemaPlaceholder">Select a table or run a query.</p><table id="schemaTable"></table>';
690
+ // Reset data display
691
+ dataDisplayContainer.innerHTML = '<h4>Data <span id="tableDataHeader"></span></h4><p id="dataPlaceholder">Select a table or run a query.</p><div id="dataDisplay"><table id="dataTable"></table></div>';
692
+ // Reset query display
693
+ queryResultContainer.style.display = 'none';
694
+ queryResultTable.innerHTML = '';
695
+
696
+ // Re-assign potentially overwritten elements after innerHTML reset
697
+ schemaTable = document.getElementById('schemaTable');
698
+ dataTable = document.getElementById('dataTable');
699
+ schemaPlaceholder = document.getElementById('schemaPlaceholder');
700
+ dataPlaceholder = document.getElementById('dataPlaceholder');
701
+ tableDataHeader = document.getElementById('tableDataHeader');
702
+ }
703
+
704
+ function resetToInitialState() {
705
+ selectedTable = null;
706
+ currentCustomSQL = '';
707
+ sqlInput.value = '';
708
+ resetDisplays();
709
+ // Make sure placeholders are visible if needed
710
+ if (currentTables.length > 0) {
711
+ schemaPlaceholder.style.display = 'block';
712
+ dataPlaceholder.style.display = 'block';
713
+ }
714
+ }
715
+
716
+
717
  // --- Polling Function ---
718
+ async function pollForUpdates() {
719
+ console.log("Polling for updates...");
720
+ try {
721
+ await loadTables(true); // Refresh table list (quietly)
722
+
723
+ if (selectedTable) {
724
+ // If a table is selected, refresh its data
725
+ await loadTableSchemaAndData(selectedTable, true);
726
+ } else if (currentCustomSQL) {
727
+ // If a custom query was last run, re-run it
728
+ await runCustomQuery(true);
729
+ }
730
+ } catch (error) {
731
+ // Errors are logged within the called functions if isPolling is true
732
+ console.error("Error during polling cycle:", error);
733
+ // Optionally stop polling on error: stopPolling(); showStatus("Polling stopped due to error.", true);
734
+ }
735
+ }
736
+
737
  function startPolling() {
738
+ stopPolling();
739
  console.log(`Starting polling every ${POLLING_INTERVAL_MS / 1000} seconds.`);
740
+ // Run immediately once, then set interval
741
+ pollForUpdates();
742
+ pollingIntervalId = setInterval(pollForUpdates, POLLING_INTERVAL_MS);
743
  }
744
 
745
  function stopPolling() {
 
751
  }
752
 
753
  // --- Initial Setup ---
754
+ runSqlButton.onclick = () => runCustomQuery(false); // Explicit run is not polling
755
 
 
756
  document.addEventListener('DOMContentLoaded', () => {
757
  loadTables().then(() => {
758
+ if (currentTables.length >= 0) { // Start polling even if empty initially
 
759
  startPolling();
760
  }
761
  });
762
  });
763
 
764
+ // Optional: Pause polling when tab is hidden
765
+ document.addEventListener("visibilitychange", () => {
766
+ if (document.visibilityState === 'hidden') {
767
+ stopPolling();
768
+ } else {
769
+ // Refresh immediately when tab becomes visible, then restart polling
770
+ loadTables().then(() => { // Refresh tables first
771
+ if (selectedTable) {
772
+ loadTableSchemaAndData(selectedTable); // Refresh data if table selected
773
+ } else if (currentCustomSQL) {
774
+ runCustomQuery(); // Refresh query if that was active
775
+ }
776
+ startPolling(); // Restart regular polling
777
+ });
778
+ }
779
+ });
780
 
781
  </script>
782