Dieser Commit ist enthalten in:
Claude Project Manager
2025-07-05 17:51:16 +02:00
Commit 0d7d888502
1594 geänderte Dateien mit 122839 neuen und 0 gelöschten Zeilen

Datei anzeigen

@ -0,0 +1,241 @@
{% extends "base.html" %}
{% block title %}License Anomalien{% endblock %}
{% block content %}
<div class="row mb-4">
<div class="col-12">
<h1 class="h3">Anomalie-Erkennung</h1>
<!-- Filter -->
<div class="card mb-3">
<div class="card-body">
<form method="get" class="row g-3">
<div class="col-md-3">
<label class="form-label">Schweregrad</label>
<select name="severity" class="form-select">
<option value="">Alle</option>
<option value="low" {% if request.args.get('severity') == 'low' %}selected{% endif %}>Niedrig</option>
<option value="medium" {% if request.args.get('severity') == 'medium' %}selected{% endif %}>Mittel</option>
<option value="high" {% if request.args.get('severity') == 'high' %}selected{% endif %}>Hoch</option>
<option value="critical" {% if request.args.get('severity') == 'critical' %}selected{% endif %}>Kritisch</option>
</select>
</div>
<div class="col-md-3">
<label class="form-label">Status</label>
<select name="resolved" class="form-select">
<option value="false" {% if request.args.get('resolved', 'false') == 'false' %}selected{% endif %}>Ungelöst</option>
<option value="true" {% if request.args.get('resolved') == 'true' %}selected{% endif %}>Gelöst</option>
<option value="">Alle</option>
</select>
</div>
<div class="col-md-3">
<label class="form-label">Anomalie-Typ</label>
<select name="anomaly_type" class="form-select">
<option value="">Alle</option>
<option value="multiple_ips" {% if request.args.get('anomaly_type') == 'multiple_ips' %}selected{% endif %}>Multiple IPs</option>
<option value="rapid_hardware_change" {% if request.args.get('anomaly_type') == 'rapid_hardware_change' %}selected{% endif %}>Schneller Hardware-Wechsel</option>
<option value="suspicious_pattern" {% if request.args.get('anomaly_type') == 'suspicious_pattern' %}selected{% endif %}>Verdächtiges Muster</option>
<option value="concurrent_use" {% if request.args.get('anomaly_type') == 'concurrent_use' %}selected{% endif %}>Gleichzeitige Nutzung</option>
</select>
</div>
<div class="col-md-3 d-flex align-items-end">
<button type="submit" class="btn btn-primary">Filter anwenden</button>
</div>
</form>
</div>
</div>
<!-- Summary Cards -->
<div class="row mb-3">
<div class="col-md-3">
<div class="card border-danger">
<div class="card-body text-center">
<h5 class="card-title text-danger">Kritisch</h5>
<h2 class="mb-0">
{% set critical_count = namespace(value=0) %}
{% for stat in anomaly_stats if stat[1] == 'critical' %}
{% set critical_count.value = critical_count.value + stat[2] %}
{% endfor %}
{{ critical_count.value }}
</h2>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-warning">
<div class="card-body text-center">
<h5 class="card-title text-warning">Hoch</h5>
<h2 class="mb-0">
{% set high_count = namespace(value=0) %}
{% for stat in anomaly_stats if stat[1] == 'high' %}
{% set high_count.value = high_count.value + stat[2] %}
{% endfor %}
{{ high_count.value }}
</h2>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-info">
<div class="card-body text-center">
<h5 class="card-title text-info">Mittel</h5>
<h2 class="mb-0">
{% set medium_count = namespace(value=0) %}
{% for stat in anomaly_stats if stat[1] == 'medium' %}
{% set medium_count.value = medium_count.value + stat[2] %}
{% endfor %}
{{ medium_count.value }}
</h2>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card">
<div class="card-body text-center">
<h5 class="card-title text-muted">Niedrig</h5>
<h2 class="mb-0">
{% set low_count = namespace(value=0) %}
{% for stat in anomaly_stats if stat[1] == 'low' %}
{% set low_count.value = low_count.value + stat[2] %}
{% endfor %}
{{ low_count.value }}
</h2>
</div>
</div>
</div>
</div>
<!-- Anomaly List -->
<div class="card">
<div class="card-header">
<h5 class="mb-0">Anomalien</h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Zeitpunkt</th>
<th>Lizenz</th>
<th>Typ</th>
<th>Schweregrad</th>
<th>Details</th>
<th>Status</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
{% for anomaly in anomalies %}
<tr class="{% if anomaly[6] == 'critical' %}table-danger{% elif anomaly[6] == 'high' %}table-warning{% endif %}">
<td>{{ anomaly[3].strftime('%d.%m.%Y %H:%M') if anomaly[3] else '-' }}</td>
<td>
{% if anomaly[8] %}
<small>{{ anomaly[8][:8] }}...</small><br>
<span class="text-muted">{{ anomaly[9] }}</span>
{% else %}
<span class="text-muted">Unbekannt</span>
{% endif %}
</td>
<td>
<span class="badge bg-secondary">{{ anomaly[5] }}</span>
</td>
<td>
<span class="badge bg-{% if anomaly[6] == 'critical' %}danger{% elif anomaly[6] == 'high' %}warning{% elif anomaly[6] == 'medium' %}info{% else %}secondary{% endif %}">
{{ anomaly[6] }}
</span>
</td>
<td>
<button class="btn btn-sm btn-link" onclick="showDetails('{{ anomaly[7] }}')">
Details anzeigen
</button>
</td>
<td>
{% if anomaly[2] %}
<span class="badge bg-success">Gelöst</span>
{% else %}
<span class="badge bg-danger">Ungelöst</span>
{% endif %}
</td>
<td>
{% if not anomaly[2] %}
<button class="btn btn-sm btn-success" onclick="resolveAnomaly('{{ anomaly[0] }}')">
Lösen
</button>
{% else %}
<small class="text-muted">{{ anomaly[4].strftime('%d.%m %H:%M') if anomaly[4] else '' }}</small>
{% endif %}
</td>
</tr>
{% else %}
<tr>
<td colspan="7" class="text-center text-muted">Keine Anomalien gefunden</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Details Modal -->
<div class="modal fade" id="detailsModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Anomalie Details</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<pre id="anomalyDetails"></pre>
</div>
</div>
</div>
</div>
<!-- Resolve Modal -->
<div class="modal fade" id="resolveModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<form id="resolveForm" method="post">
<div class="modal-header">
<h5 class="modal-title">Anomalie lösen</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Ergriffene Maßnahme</label>
<textarea name="action_taken" class="form-control" rows="3" required></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
<button type="submit" class="btn btn-success">Als gelöst markieren</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
function showDetails(detailsJson) {
try {
const details = JSON.parse(detailsJson);
document.getElementById('anomalyDetails').textContent = JSON.stringify(details, null, 2);
new bootstrap.Modal(document.getElementById('detailsModal')).show();
} catch (e) {
alert('Fehler beim Anzeigen der Details');
}
}
function resolveAnomaly(anomalyId) {
const form = document.getElementById('resolveForm');
form.action = `/lizenzserver/anomaly/${anomalyId}/resolve`;
new bootstrap.Modal(document.getElementById('resolveModal')).show();
}
</script>
{% endblock %}