Fix: Tab-Navigation + Umlaute in app.js

sourceSubTabs vom Haupt-Navigation-Handler ausgeschlossen -
verhindert dass Source-Sub-Tabs die Hauptnavigation stören
und Inhalte unterhalb anderer Tabs angezeigt werden.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dieser Commit ist enthalten in:
claude-dev
2026-03-08 16:38:26 +01:00
Ursprung 75dd9b0669
Commit fb5ed358bd

Datei anzeigen

@@ -54,10 +54,10 @@ function logout() {
// --- Navigation --- // --- Navigation ---
function setupNavTabs() { function setupNavTabs() {
document.querySelectorAll(".nav-tabs:not(#orgDetailTabs) .nav-tab").forEach(tab => { document.querySelectorAll(".nav-tabs:not(#orgDetailTabs):not(#sourceSubTabs) .nav-tab").forEach(tab => {
tab.addEventListener("click", () => { tab.addEventListener("click", () => {
const section = tab.dataset.section; const section = tab.dataset.section;
document.querySelectorAll(".nav-tabs:not(#orgDetailTabs) .nav-tab").forEach(t => t.classList.remove("active")); document.querySelectorAll(".nav-tabs:not(#orgDetailTabs):not(#sourceSubTabs) .nav-tab").forEach(t => t.classList.remove("active"));
tab.classList.add("active"); tab.classList.add("active");
document.querySelectorAll(".app-content > .section").forEach(s => s.classList.remove("active")); document.querySelectorAll(".app-content > .section").forEach(s => s.classList.remove("active"));
document.getElementById(`sec-${section}`).classList.add("active"); document.getElementById(`sec-${section}`).classList.add("active");
@@ -106,7 +106,7 @@ async function loadDashboard() {
<div class="stat-value">${stats.licenses.active}</div> <div class="stat-value">${stats.licenses.active}</div>
</div> </div>
<div class="stat-card"> <div class="stat-card">
<div class="stat-label">Vorfaelle</div> <div class="stat-label">Vorfälle</div>
<div class="stat-value">${stats.incidents.total}</div> <div class="stat-value">${stats.incidents.total}</div>
<div class="stat-sub">${stats.incidents.active} aktiv</div> <div class="stat-sub">${stats.incidents.active} aktiv</div>
</div> </div>
@@ -128,7 +128,7 @@ async function loadDashboard() {
// Recent activity // Recent activity
const actEl = document.getElementById("recentActivity"); const actEl = document.getElementById("recentActivity");
if (stats.recent_activity.length === 0) { if (stats.recent_activity.length === 0) {
actEl.innerHTML = '<div class="text-muted">Keine Aktivitaet</div>'; actEl.innerHTML = '<div class="text-muted">Keine Aktivität</div>';
} else { } else {
actEl.innerHTML = stats.recent_activity.map(a => ` actEl.innerHTML = stats.recent_activity.map(a => `
<div class="activity-item"> <div class="activity-item">
@@ -250,7 +250,7 @@ async function loadOrgUsers(orgId) {
? `<button class="btn btn-secondary btn-small" onclick="toggleUser(${u.id}, false)">Deaktivieren</button>` ? `<button class="btn btn-secondary btn-small" onclick="toggleUser(${u.id}, false)">Deaktivieren</button>`
: `<button class="btn btn-success btn-small" onclick="toggleUser(${u.id}, true)">Aktivieren</button>` : `<button class="btn btn-success btn-small" onclick="toggleUser(${u.id}, true)">Aktivieren</button>`
} }
<button class="btn btn-danger btn-small" onclick="confirmDeleteUser(${u.id}, '${esc(u.email)}')">Loeschen</button> <button class="btn btn-danger btn-small" onclick="confirmDeleteUser(${u.id}, '${esc(u.email)}')">Löschen</button>
</td> </td>
</tr> </tr>
`).join(""); `).join("");
@@ -279,8 +279,8 @@ async function toggleUser(userId, activate) {
function confirmDeleteUser(userId, email) { function confirmDeleteUser(userId, email) {
showConfirm( showConfirm(
"Nutzer loeschen", "Nutzer löschen",
`Soll der Nutzer "${email}" endgueltig geloescht werden?`, `Soll der Nutzer "${email}" endgültig gelöscht werden?`,
async () => { async () => {
try { try {
await API.del(`/api/users/${userId}`); await API.del(`/api/users/${userId}`);
@@ -310,7 +310,7 @@ async function loadOrgLicenses(orgId) {
<td><span class="badge badge-${l.status}">${l.status}</span></td> <td><span class="badge badge-${l.status}">${l.status}</span></td>
<td> <td>
${l.status === "active" ? ` ${l.status === "active" ? `
<button class="btn btn-secondary btn-small" onclick="extendLicense(${l.id})">Verlaengern</button> <button class="btn btn-secondary btn-small" onclick="extendLicense(${l.id})">Verlängern</button>
<button class="btn btn-danger btn-small" onclick="confirmRevokeLicense(${l.id})">Widerrufen</button> <button class="btn btn-danger btn-small" onclick="confirmRevokeLicense(${l.id})">Widerrufen</button>
` : ""} ` : ""}
</td> </td>
@@ -322,7 +322,7 @@ async function loadOrgLicenses(orgId) {
} }
async function extendLicense(licId) { async function extendLicense(licId) {
const days = prompt("Um wie viele Tage verlaengern?", "365"); const days = prompt("Um wie viele Tage verlängern?", "365");
if (!days) return; if (!days) return;
try { try {
await API.put(`/api/licenses/${licId}/extend?days=${parseInt(days)}`); await API.put(`/api/licenses/${licId}/extend?days=${parseInt(days)}`);
@@ -335,7 +335,7 @@ async function extendLicense(licId) {
function confirmRevokeLicense(licId) { function confirmRevokeLicense(licId) {
showConfirm( showConfirm(
"Lizenz widerrufen", "Lizenz widerrufen",
"Soll die Lizenz wirklich widerrufen werden? Nutzer koennen dann nur noch lesen.", "Soll die Lizenz wirklich widerrufen werden? Nutzer können dann nur noch lesen.",
async () => { async () => {
try { try {
await API.put(`/api/licenses/${licId}/revoke`); await API.put(`/api/licenses/${licId}/revoke`);
@@ -354,7 +354,7 @@ async function loadExpiringLicenses() {
const licenses = await API.get(`/api/licenses/expiring?days=${days}`); const licenses = await API.get(`/api/licenses/expiring?days=${days}`);
const tbody = document.getElementById("expiringTable"); const tbody = document.getElementById("expiringTable");
if (licenses.length === 0) { if (licenses.length === 0) {
tbody.innerHTML = `<tr><td colspan="5" class="text-muted">Keine ablaufenden Lizenzen in den naechsten ${days} Tagen</td></tr>`; tbody.innerHTML = `<tr><td colspan="5" class="text-muted">Keine ablaufenden Lizenzen in den nächsten ${days} Tagen</td></tr>`;
return; return;
} }
tbody.innerHTML = licenses.map(l => ` tbody.innerHTML = licenses.map(l => `
@@ -364,7 +364,7 @@ async function loadExpiringLicenses() {
<td>${l.max_users}</td> <td>${l.max_users}</td>
<td class="text-warning">${formatDate(l.valid_until)}</td> <td class="text-warning">${formatDate(l.valid_until)}</td>
<td> <td>
<button class="btn btn-secondary btn-small" onclick="extendLicense(${l.id})">Verlaengern</button> <button class="btn btn-secondary btn-small" onclick="extendLicense(${l.id})">Verlängern</button>
</td> </td>
</tr> </tr>
`).join(""); `).join("");
@@ -380,7 +380,7 @@ document.addEventListener("DOMContentLoaded", () => {
function switchToOrg(orgId) { function switchToOrg(orgId) {
// Switch to orgs tab and open detail // Switch to orgs tab and open detail
document.querySelectorAll(".nav-tabs:not(#orgDetailTabs) .nav-tab").forEach(t => t.classList.remove("active")); document.querySelectorAll(".nav-tabs:not(#orgDetailTabs):not(#sourceSubTabs) .nav-tab").forEach(t => t.classList.remove("active"));
document.querySelector('.nav-tab[data-section="orgs"]').classList.add("active"); document.querySelector('.nav-tab[data-section="orgs"]').classList.add("active");
document.querySelectorAll(".app-content > .section").forEach(s => s.classList.remove("active")); document.querySelectorAll(".app-content > .section").forEach(s => s.classList.remove("active"));
document.getElementById("sec-orgs").classList.add("active"); document.getElementById("sec-orgs").classList.add("active");
@@ -495,8 +495,8 @@ function setupForms() {
// Delete Org // Delete Org
document.getElementById("deleteOrgBtn").addEventListener("click", () => { document.getElementById("deleteOrgBtn").addEventListener("click", () => {
showConfirm( showConfirm(
"Organisation loeschen", "Organisation löschen",
"Soll die Organisation mit allen Nutzern und Lizenzen endgueltig geloescht werden? Diese Aktion kann nicht rueckgaengig gemacht werden.", "Soll die Organisation mit allen Nutzern und Lizenzen endgültig gelöscht werden? Diese Aktion kann nicht rückgängig gemacht werden.",
async () => { async () => {
try { try {
await API.del(`/api/orgs/${currentOrgId}`); await API.del(`/api/orgs/${currentOrgId}`);