amaye15 commited on
Commit
3590e8f
·
1 Parent(s): 2de1f9e
Files changed (1) hide show
  1. index.html +127 -198
index.html CHANGED
@@ -382,16 +382,17 @@
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,20 +402,16 @@
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,8 +426,8 @@
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,28 +440,25 @@
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,14 +486,17 @@
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,6 +504,7 @@
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,52 +513,67 @@
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,6 +588,7 @@
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,48 +596,7 @@
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,115 +604,75 @@
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,32 +684,28 @@
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
 
 
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
  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
  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
  } 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
  });
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
  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
  });
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
  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
  });
597
  }
598
 
599
+ async function handleTableSelection(listItem) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
  const currentActive = tableList.querySelector('.active');
601
  if (currentActive) {
602
  currentActive.classList.remove('active');
 
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
  }
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