// ── Database Explorer Page ── registerPage('db-explorer', { async init() { if (!currentUser || !currentUser.isAdmin) { navigateTo('dashboard'); return; } var titleEl = document.getElementById('dbExplorerTitle'); var contentEl = document.getElementById('dbExplorerContent'); var currentTable = null; await loadTables(); async function loadTables() { currentTable = null; titleEl.textContent = 'Datenbank-Explorer'; try { var resp = await fetch('/api/admin/db/tables'); var data = await resp.json(); contentEl.innerHTML = ''; var table = document.createElement('table'); table.className = 'db-table'; var thead = document.createElement('thead'); thead.innerHTML = 'TabelleSpaltenZeilen'; table.appendChild(thead); var tbody = document.createElement('tbody'); data.tables.forEach(function(t) { var tr = document.createElement('tr'); tr.className = 'db-table-row clickable'; var tdName = document.createElement('td'); tdName.innerHTML = ' ' + esc(t.name); tdName.className = 'db-table-name'; var tdCols = document.createElement('td'); tdCols.textContent = t.columns; tdCols.className = 'db-table-num'; var tdRows = document.createElement('td'); tdRows.textContent = t.rows.toLocaleString(); tdRows.className = 'db-table-num'; tr.appendChild(tdName); tr.appendChild(tdCols); tr.appendChild(tdRows); tr.addEventListener('click', function() { loadTableData(t.name, -1); }); tbody.appendChild(tr); }); table.appendChild(tbody); contentEl.appendChild(table); } catch (err) { contentEl.innerHTML = '

Fehler beim Laden: ' + esc(err.message) + '

'; } } async function loadTableData(name, page) { currentTable = name; titleEl.innerHTML = 'Datenbank-Explorer ' + esc(name); // Back-Link klickbar titleEl.querySelector('.db-back-link').classList.add('clickable'); titleEl.querySelector('.db-back-link').addEventListener('click', function() { loadTables(); }); try { var resp = await fetch('/api/admin/db/tables/' + encodeURIComponent(name) + '?page=' + page + '&pageSize=1000'); var data = await resp.json(); page = data.pagination.page; contentEl.innerHTML = ''; // Info-Zeile var info = document.createElement('div'); info.className = 'db-info-bar'; info.innerHTML = '' + data.pagination.totalRows.toLocaleString() + ' Zeilen'; // Pagination if (data.pagination.totalPages > 1) { var pagDiv = document.createElement('span'); pagDiv.className = 'db-pagination'; if (page > 1) { var prevBtn = document.createElement('button'); prevBtn.className = 'btn btn-small'; prevBtn.innerHTML = ''; prevBtn.addEventListener('click', function() { loadTableData(name, page - 1); }); pagDiv.appendChild(prevBtn); } var pageInfo = document.createElement('span'); pageInfo.className = 'db-page-info'; pageInfo.textContent = 'Seite ' + page + ' / ' + data.pagination.totalPages; pagDiv.appendChild(pageInfo); if (page < data.pagination.totalPages) { var nextBtn = document.createElement('button'); nextBtn.className = 'btn btn-small'; nextBtn.innerHTML = ''; nextBtn.addEventListener('click', function() { loadTableData(name, page + 1); }); pagDiv.appendChild(nextBtn); } info.appendChild(pagDiv); } contentEl.appendChild(info); // Tabelle mit Daten var wrapper = document.createElement('div'); wrapper.className = 'db-table-wrapper'; var table = document.createElement('table'); table.className = 'db-table db-data-table'; // Header aus Spalten-Info var thead = document.createElement('thead'); var headerRow = document.createElement('tr'); data.columns.forEach(function(col) { var th = document.createElement('th'); th.textContent = col.name; if (col.pk) th.innerHTML += ' '; th.title = col.type + (col.notnull ? ' NOT NULL' : '') + (col.pk ? ' PRIMARY KEY' : ''); headerRow.appendChild(th); }); thead.appendChild(headerRow); table.appendChild(thead); // Body var tbody = document.createElement('tbody'); if (data.rows.length === 0) { var emptyRow = document.createElement('tr'); var emptyCell = document.createElement('td'); emptyCell.colSpan = data.columns.length; emptyCell.className = 'db-empty'; emptyCell.textContent = 'Keine Daten'; emptyRow.appendChild(emptyCell); tbody.appendChild(emptyRow); } else { data.rows.forEach(function(row) { var tr = document.createElement('tr'); data.columns.forEach(function(col) { var td = document.createElement('td'); var val = row[col.name]; if (val === null || val === undefined) { td.innerHTML = 'NULL'; } else { var str = String(val); if (str.length > 120) { td.textContent = str.substring(0, 120) + '…'; td.title = str; } else { td.textContent = str; } } tr.appendChild(td); }); tbody.appendChild(tr); }); } table.appendChild(tbody); wrapper.appendChild(table); contentEl.appendChild(wrapper); } catch (err) { contentEl.innerHTML = '

Fehler beim Laden: ' + esc(err.message) + '

'; } } }, destroy() {} });