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:
@@ -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}`);
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren