Quelltext des aktuellen Standes
/**
* IT-Dokumentation - Admin JavaScript
* Admin-Bereich spezifische Funktionen
*/
'use strict';
window.OpenNIT = window.OpenNIT || {};
OpenNIT.Admin = OpenNIT.Admin || {};
/**
* Admin-Initialisierung
*/
document.addEventListener('DOMContentLoaded', function() {
OpenNIT.Admin.init();
});
/**
* Hauptinitialisierung
*/
OpenNIT.Admin.init = function() {
this.initDataTables();
this.initBulkActions();
this.initCharts();
this.initAuditFilters();
};
/**
* Daten-Tabellen erweitern
*/
OpenNIT.Admin.initDataTables = function() {
// Sortierbare Spalten
document.querySelectorAll('.data-table .sort-link').forEach(function(link) {
link.addEventListener('click', function(e) {
// Lade-Indikator
this.style.opacity = '0.5';
});
});
// Zeilen-Aktionen
document.querySelectorAll('.data-table tbody tr').forEach(function(row) {
// Doppelklick zum Bearbeiten
row.addEventListener('dblclick', function() {
const editLink = this.querySelector('a[title="Bearbeiten"]');
if (editLink) {
window.location.href = editLink.href;
}
});
});
};
/**
* Massenaktionen
*/
OpenNIT.Admin.initBulkActions = function() {
const selectAll = document.querySelector('.bulk-select-all');
if (!selectAll) return;
const checkboxes = document.querySelectorAll('.bulk-select');
const bulkActions = document.querySelector('.bulk-actions');
// Alle auswählen
selectAll.addEventListener('change', function() {
checkboxes.forEach(function(cb) {
cb.checked = selectAll.checked;
});
OpenNIT.Admin.updateBulkActions(bulkActions, checkboxes);
});
// Einzelne Checkboxen
checkboxes.forEach(function(cb) {
cb.addEventListener('change', function() {
OpenNIT.Admin.updateBulkActions(bulkActions, checkboxes);
// "Alle auswählen" Status aktualisieren
const checkedCount = document.querySelectorAll('.bulk-select:checked').length;
selectAll.checked = checkedCount === checkboxes.length;
selectAll.indeterminate = checkedCount > 0 && checkedCount < checkboxes.length;
});
});
};
/**
* Massenaktionen-UI aktualisieren
*/
OpenNIT.Admin.updateBulkActions = function(container, checkboxes) {
if (!container) return;
const checkedCount = document.querySelectorAll('.bulk-select:checked').length;
if (checkedCount > 0) {
container.style.display = 'flex';
container.querySelector('.selected-count').textContent = checkedCount + ' ' + window.onitText('ausgewählt');
} else {
container.style.display = 'none';
}
};
/**
* Charts initialisieren (wenn vorhanden)
*/
OpenNIT.Admin.initCharts = function() {
// Einfaches Balkendiagramm für Audit-Statistiken
document.querySelectorAll('[data-chart="bar"]').forEach(function(container) {
const data = JSON.parse(container.dataset.values || '[]');
OpenNIT.Admin.renderBarChart(container, data);
});
};
/**
* Einfaches Balkendiagramm rendern
*/
OpenNIT.Admin.renderBarChart = function(container, data) {
if (!data.length) return;
const maxValue = Math.max(...data.map(function(d) { return d.value; }));
let html = '<div class="simple-bar-chart">';
data.forEach(function(item) {
const percentage = maxValue > 0 ? (item.value / maxValue) * 100 : 0;
html += '<div class="bar-item">';
html += '<span class="bar-label">' + OpenNIT.escapeHtml(item.label) + '</span>';
html += '<div class="bar-track"><div class="bar-fill" style="width: ' + percentage + '%"></div></div>';
html += '<span class="bar-value">' + item.value + '</span>';
html += '</div>';
});
html += '</div>';
container.innerHTML = html;
};
/**
* Audit-Filter
*/
OpenNIT.Admin.initAuditFilters = function() {
const filterForm = document.querySelector('.audit-page .filter-form');
if (!filterForm) return;
// Auto-Submit bei Select-Änderung
filterForm.querySelectorAll('select').forEach(function(select) {
select.addEventListener('change', function() {
// Debounce für schnelle Änderungen
clearTimeout(this._submitTimeout);
this._submitTimeout = setTimeout(function() {
filterForm.submit();
}, 300);
});
});
// Datum-Validierung
const dateFrom = filterForm.querySelector('input[name="date_from"]');
const dateTo = filterForm.querySelector('input[name="date_to"]');
if (dateFrom && dateTo) {
dateFrom.addEventListener('change', function() {
dateTo.min = this.value;
});
dateTo.addEventListener('change', function() {
dateFrom.max = this.value;
});
}
};
/**
* Benutzer deaktivieren
*/
OpenNIT.Admin.deactivateUser = function(userId, userName) {
if (!confirm('Benutzer "' + userName + '" wirklich deaktivieren?\n\nDer Benutzer kann sich danach nicht mehr anmelden.')) {
return;
}
OpenNIT.fetch('/admin/users/' + userId + '/deactivate', {
method: 'POST'
})
.then(function(response) {
return response.json();
})
.then(function(data) {
if (data.success) {
OpenNIT.notify('Benutzer deaktiviert', 'success');
window.location.reload();
} else {
OpenNIT.notify(data.error || 'Fehler beim Deaktivieren', 'error');
}
})
.catch(function() {
OpenNIT.notify('Fehler beim Deaktivieren', 'error');
});
};
/**
* Benutzer aktivieren
*/
OpenNIT.Admin.activateUser = function(userId, userName) {
OpenNIT.fetch('/admin/users/' + userId + '/activate', {
method: 'POST'
})
.then(function(response) {
return response.json();
})
.then(function(data) {
if (data.success) {
OpenNIT.notify('Benutzer aktiviert', 'success');
window.location.reload();
} else {
OpenNIT.notify(data.error || 'Fehler beim Aktivieren', 'error');
}
})
.catch(function() {
OpenNIT.notify('Fehler beim Aktivieren', 'error');
});
};
/**
* Rolle löschen
*/
OpenNIT.Admin.deleteRole = function(roleId, roleName) {
if (!confirm(window.onitText('Rolle „{name}“ wirklich löschen?').replace('{name}', roleName)
+ '\n\n' + window.onitText('Diese Aktion kann nicht rückgängig gemacht werden.'))) {
return;
}
OpenNIT.fetch('/admin/roles/' + roleId + '/delete', {
method: 'POST'
})
.then(function(response) {
return response.json();
})
.then(function(data) {
if (data.success) {
OpenNIT.notify(window.onitText('Rolle gelöscht'), 'success');
window.location.href = '/admin/roles';
} else {
OpenNIT.notify(data.error || window.onitText('Fehler beim Löschen'), 'error');
}
})
.catch(function() {
OpenNIT.notify(window.onitText('Fehler beim Löschen'), 'error');
});
};
/**
* Audit-Export
*/
OpenNIT.Admin.exportAudit = function(format) {
const params = new URLSearchParams(window.location.search);
params.set('format', format);
window.location.href = '/admin/audit/export?' + params.toString();
};
/**
* Hash-Kette verifizieren
*/
OpenNIT.Admin.verifyHashChain = function(startId, limit) {
const button = document.querySelector('.verify-btn');
if (button) {
button.disabled = true;
button.textContent = 'Verifiziere...';
}
OpenNIT.fetch('/admin/audit/verify?start_id=' + startId + '&limit=' + limit)
.then(function(response) {
return response.json();
})
.then(function(data) {
if (data.valid) {
OpenNIT.notify(window.onitText('Alle {anzahl} Einträge sind integer').replace('{anzahl}', data.verified_count), 'success');
} else {
OpenNIT.notify(window.onitText('Integritätsfehler bei {anzahl} Einträgen gefunden!').replace('{anzahl}', data.error_count), 'error');
}
if (button) {
button.disabled = false;
button.textContent = 'Verifizieren';
}
})
.catch(function() {
OpenNIT.notify('Fehler bei der Verifizierung', 'error');
if (button) {
button.disabled = false;
button.textContent = 'Verifizieren';
}
});
};
/**
* Berechtigungs-Matrix Toggle
*/
OpenNIT.Admin.togglePermission = function(userId, topicId, roleId, checkbox) {
const action = checkbox.checked ? 'grant' : 'revoke';
OpenNIT.fetch('/admin/permissions/' + action, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
user_id: userId,
topic_id: topicId,
role_id: roleId
})
})
.then(function(response) {
return response.json();
})
.then(function(data) {
if (data.success) {
OpenNIT.notify(action === 'grant' ? 'Berechtigung erteilt' : 'Berechtigung entzogen', 'success');
} else {
checkbox.checked = !checkbox.checked; // Zurücksetzen
OpenNIT.notify(data.error || 'Fehler', 'error');
}
})
.catch(function() {
checkbox.checked = !checkbox.checked; // Zurücksetzen
OpenNIT.notify('Fehler beim Speichern', 'error');
});
};
/**
* Review-Status aktualisieren
*/
OpenNIT.Admin.completeReview = function(pageId, button) {
if (!confirm('Review als abgeschlossen markieren?')) {
return;
}
button.disabled = true;
button.textContent = 'Wird gespeichert...';
OpenNIT.fetch('/pages/' + pageId + '/responsibilities/complete-review', {
method: 'POST'
})
.then(function(response) {
return response.json();
})
.then(function(data) {
if (data.success) {
OpenNIT.notify('Review abgeschlossen', 'success');
window.location.reload();
} else {
button.disabled = false;
button.textContent = window.onitText('Review abschließen');
OpenNIT.notify(data.error || 'Fehler', 'error');
}
})
.catch(function() {
button.disabled = false;
button.textContent = window.onitText('Review abschließen');
OpenNIT.notify('Fehler beim Speichern', 'error');
});
};