// JavaScript für Query Builder Funktionalität
// Globale Variablen
let currentTables = [];
let savedQueries = [];
let currentConnection = 'oracle';
// Lade verfügbare Datenbankverbindungen
function loadConnections() {
fetch('/get_connections')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json();
})
.then(data => {
const selector = document.getElementById('database-selector');
if (!selector) {
console.warn('Database selector nicht gefunden');
return;
}
selector.innerHTML = '';
if (data.success && data.connections && data.connections.length > 0) {
data.connections.forEach(conn => {
const option = document.createElement('option');
option.value = conn.key;
option.textContent = `${conn.name} (${conn.type})`;
option.title = conn.description;
if (conn.key === 'oracle') {
option.selected = true;
currentConnection = 'oracle';
}
selector.appendChild(option);
});
// Lade Tabellen für die ausgewählte Verbindung
loadTables();
} else {
const option = document.createElement('option');
option.textContent = data.error || 'Keine Verbindungen verfügbar';
selector.appendChild(option);
console.error('API-Fehler:', data.error);
}
})
.catch(error => {
console.error('Netzwerk-Fehler beim Laden der Verbindungen:', error);
const selector = document.getElementById('database-selector');
if (selector) {
selector.innerHTML = ``;
}
});
}
// Datenbankauswahl geändert
function onDatabaseChange() {
const selector = document.getElementById('database-selector');
if (selector) {
currentConnection = selector.value;
loadTables();
}
}
// Utility Functions
function showLoading(elementId) {
const element = document.getElementById(elementId);
if (element) {
element.innerHTML = '
Query erfolgreich, aber keine Ergebnisse gefunden.
`;
return;
}
// Erstelle Tabelle mit Ergebnissen
const tableHtml = `
${results.row_count} Zeile(n) gefunden
${results.columns.map(col => `| ${col} | `).join('')}
${results.data.map(row => `
${row.map(cell => `| ${cell !== null ? cell : 'NULL'} | `).join('')}
`).join('')}
`;
resultsContainer.innerHTML = tableHtml;
}
// Query speichern
function showSaveQueryModal(event) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
const queryInput = document.getElementById('query-input');
const query = queryInput.value.trim();
if (!query) {
showAlert('Bitte geben Sie eine Query ein', 'error');
return false;
}
// Reset des Modal-Formulars
const queryNameInput = document.getElementById('query-name');
if (queryNameInput) {
queryNameInput.value = '';
}
// Modal anzeigen - alternative Methode
const modalElement = document.getElementById('saveQueryModal');
if (modalElement) {
// Prüfe ob Bootstrap verfügbar ist
if (typeof bootstrap !== 'undefined' && bootstrap.Modal) {
const modal = new bootstrap.Modal(modalElement, {
backdrop: true,
keyboard: true,
focus: true
});
modal.show();
// Fokus auf Name-Input setzen nach Modal-Öffnung
modalElement.addEventListener('shown.bs.modal', function() {
const nameInput = document.getElementById('query-name');
if (nameInput) {
nameInput.focus();
}
}, { once: true });
} else {
// Fallback: Zeige Modal manuell
modalElement.style.display = 'block';
modalElement.classList.add('show');
modalElement.setAttribute('aria-modal', 'true');
modalElement.setAttribute('role', 'dialog');
document.body.classList.add('modal-open');
// Backdrop hinzufügen
const backdrop = document.createElement('div');
backdrop.className = 'modal-backdrop fade show';
backdrop.id = 'manual-modal-backdrop';
document.body.appendChild(backdrop);
}
}
return false;
}
// Funktion zum manuellen Schließen des Modals (Fallback)
function closeModalManually() {
const modalElement = document.getElementById('saveQueryModal');
const backdrop = document.getElementById('manual-modal-backdrop');
if (modalElement) {
modalElement.style.display = 'none';
modalElement.classList.remove('show');
modalElement.removeAttribute('aria-modal');
modalElement.removeAttribute('role');
document.body.classList.remove('modal-open');
}
if (backdrop) {
backdrop.remove();
}
}
async function saveQuery() {
const name = document.getElementById('query-name').value.trim();
const query = document.getElementById('query-input').value.trim();
if (!name || !query) {
showAlert('Name und Query sind erforderlich', 'error');
return;
}
try {
const response = await fetch('/save_query', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: name,
description: '', // Keine Beschreibung mehr
query: query
})
});
const data = await response.json();
if (data.success) {
showAlert('Query erfolgreich gespeichert');
// Modal schließen
if (typeof bootstrap !== 'undefined' && bootstrap.Modal) {
const modal = bootstrap.Modal.getInstance(document.getElementById('saveQueryModal'));
if (modal) {
modal.hide();
} else {
closeModalManually();
}
} else {
closeModalManually();
}
// Input-Feld zurücksetzen
document.getElementById('query-name').value = '';
// Seite neu laden um gespeicherte Queries zu aktualisieren
setTimeout(() => window.location.reload(), 1000);
} else {
showAlert(data.error, 'error');
}
} catch (error) {
showAlert(`Fehler beim Speichern: ${error.message}`, 'error');
}
}
// Gespeicherte Query laden
function loadSavedQuery(queryId, queryText) {
const queryInput = document.getElementById('query-input');
if (queryInput.value.trim() && !confirm('Dies wird die aktuelle Query ersetzen. Fortfahren?')) {
return;
}
queryInput.value = queryText;
}
// Gespeicherte Query löschen
async function deleteSavedQuery(queryId) {
if (!confirm('Möchten Sie diese gespeicherte Query wirklich löschen?')) {
return;
}
try {
const response = await fetch(`/delete_query/${queryId}`, {
method: 'DELETE'
});
const data = await response.json();
if (data.success) {
showAlert('Query erfolgreich gelöscht');
// Query-Element entfernen
const queryCard = document.querySelector(`[data-query-id="${queryId}"]`);
if (queryCard) {
queryCard.remove();
}
} else {
showAlert(data.error, 'error');
}
} catch (error) {
showAlert(`Fehler beim Löschen: ${error.message}`, 'error');
}
}
// Neue Funktionen für die verbesserte Query-Verwaltung
// Gespeicherte Queries filtern
function filterSavedQueries() {
const searchTerm = document.getElementById('search-queries').value.toLowerCase();
const queryCards = document.querySelectorAll('.saved-query-card');
queryCards.forEach(card => {
const queryName = card.querySelector('h6').textContent.toLowerCase();
const queryText = card.dataset.queryText ? card.dataset.queryText.toLowerCase() : '';
if (queryName.includes(searchTerm) || queryText.includes(searchTerm)) {
card.style.display = 'block';
} else {
card.style.display = 'none';
}
});
}
// Query-Name bearbeiten
let currentEditQueryId = null;
function editQueryName(queryId, currentName) {
currentEditQueryId = queryId;
document.getElementById('edit-query-name').value = currentName;
// Modal öffnen
if (typeof bootstrap !== 'undefined' && bootstrap.Modal) {
const modal = new bootstrap.Modal(document.getElementById('editQueryModal'));
modal.show();
} else {
document.getElementById('editQueryModal').style.display = 'block';
}
}
async function updateQueryName() {
const newName = document.getElementById('edit-query-name').value.trim();
if (!newName) {
showAlert('Name ist erforderlich', 'error');
return;
}
try {
const response = await fetch(`/update_query_name/${currentEditQueryId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: newName })
});
const data = await response.json();
if (data.success) {
showAlert('Query-Name erfolgreich aktualisiert');
// Modal schließen
if (typeof bootstrap !== 'undefined' && bootstrap.Modal) {
const modal = bootstrap.Modal.getInstance(document.getElementById('editQueryModal'));
if (modal) {
modal.hide();
}
} else {
document.getElementById('editQueryModal').style.display = 'none';
}
// Seite neu laden
setTimeout(() => window.location.reload(), 1000);
} else {
showAlert(data.error, 'error');
}
} catch (error) {
showAlert(`Fehler beim Aktualisieren: ${error.message}`, 'error');
}
}
// Query duplizieren
async function duplicateQuery(queryId, queryName, queryText) {
const newName = prompt(`Neuer Name für die Kopie von "${queryName}":`, `${queryName} (Kopie)`);
if (!newName || newName.trim() === '') {
return;
}
try {
const response = await fetch('/save_query', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: newName.trim(),
description: '',
query: queryText
})
});
const data = await response.json();
if (data.success) {
showAlert('Query erfolgreich dupliziert');
setTimeout(() => window.location.reload(), 1000);
} else {
showAlert(data.error, 'error');
}
} catch (error) {
showAlert(`Fehler beim Duplizieren: ${error.message}`, 'error');
}
}
// Query per Name ausführen (für API)
async function executeQueryByName(queryName) {
try {
// Öffne Ergebnisse in neuem Tab als CSV
window.open(`/api/queries/${encodeURIComponent(queryName)}/export/csv`, '_blank');
} catch (error) {
showAlert(`Fehler beim Export: ${error.message}`, 'error');
}
}
// Query löschen
function clearQuery() {
if (confirm('Möchten Sie die aktuelle Query löschen?')) {
document.getElementById('query-input').value = '';
}
}
// Ergebnisse exportieren
function exportResults(format) {
const query = document.getElementById('query-input').value.trim();
if (!query) {
showAlert('Keine Query zum Exportieren vorhanden', 'error');
return;
}
// Erstelle temporäre Form für Export
const form = document.createElement('form');
form.method = 'POST';
form.action = '/execute_query';
form.style.display = 'none';
const queryField = document.createElement('input');
queryField.name = 'query';
queryField.value = query;
const formatField = document.createElement('input');
formatField.name = 'format';
formatField.value = format;
form.appendChild(queryField);
form.appendChild(formatField);
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
}
// Keyboard Shortcuts
document.addEventListener('keydown', function(e) {
// Ctrl+Enter oder Cmd+Enter für Query ausführen
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
e.preventDefault();
executeQuery();
}
// Ctrl+S oder Cmd+S für Query speichern
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
e.preventDefault();
showSaveQueryModal();
}
});
// Auto-resize für Textarea
document.addEventListener('DOMContentLoaded', function() {
// Lade Verbindungen beim Seitenstart
loadConnections();
// Spalten-Anzeige basierend auf gespeicherten Einstellungen initialisieren
updateColumnsView();
const queryInput = document.getElementById('query-input');
if (queryInput) {
queryInput.addEventListener('input', function() {
this.style.height = 'auto';
this.style.height = Math.max(150, this.scrollHeight) + 'px';
});
// Drag & Drop Event-Listener für Query-Input
setupQueryInputDropZone(queryInput);
}
// Event-Listener für Save Query Buttons
const saveQueryBtn = document.getElementById('save-query-btn');
if (saveQueryBtn) {
saveQueryBtn.addEventListener('click', function(event) {
event.preventDefault();
event.stopPropagation();
showSaveQueryModal(event);
});
}
const saveQueryBtnSidebar = document.getElementById('save-query-btn-sidebar');
if (saveQueryBtnSidebar) {
saveQueryBtnSidebar.addEventListener('click', function(event) {
event.preventDefault();
event.stopPropagation();
showSaveQueryModal(event);
});
}
});
// Globale Variable für Spalten-Anzeige Status
let columnsVisible = localStorage.getItem('columnsVisible') !== 'false'; // Standard: true
// Funktion zum Ein-/Ausblenden der Spalten-Anzeige
function toggleColumnsView() {
columnsVisible = !columnsVisible;
localStorage.setItem('columnsVisible', columnsVisible.toString());
updateColumnsView();
}
// Funktion zum Aktualisieren der Spalten-Anzeige basierend auf dem Status
function updateColumnsView() {
const toggleBtn = document.getElementById('toggle-columns-btn');
const allColumns = document.querySelectorAll('.table-columns');
if (columnsVisible) {
// Spalten anzeigen
allColumns.forEach(col => {
if (col.parentElement.querySelector('.table-item.selected')) {
col.style.display = 'block';
}
});
if (toggleBtn) {
toggleBtn.innerHTML = '