Test zu Fake geändert, weil Namensproblem

Dieser Commit ist enthalten in:
2025-06-21 17:22:12 +02:00
Ursprung fec588ba06
Commit 3d899b1c45
22 geänderte Dateien mit 614 neuen und 347 gelöschten Zeilen

Datei anzeigen

@@ -175,9 +175,9 @@
<!-- Test Data Checkbox -->
<div class="form-check mt-3">
<input class="form-check-input" type="checkbox" id="isTest" name="is_test">
<label class="form-check-label" for="isTest">
<i class="fas fa-flask"></i> Als Testdaten markieren
<input class="form-check-input" type="checkbox" id="isFake" name="is_fake">
<label class="form-check-label" for="isFake">
<i class="fas fa-flask"></i> Als Fake-Daten markieren
<small class="text-muted">(wird von der Software ignoriert)</small>
</label>
</div>

Datei anzeigen

@@ -30,9 +30,9 @@
</div>
<div class="form-check mt-3">
<input class="form-check-input" type="checkbox" id="isTest" name="is_test">
<label class="form-check-label" for="isTest">
<i class="fas fa-flask"></i> Als Testdaten markieren
<input class="form-check-input" type="checkbox" id="isFake" name="is_fake">
<label class="form-check-label" for="isFake">
<i class="fas fa-flask"></i> Als Fake-Daten markieren
<small class="text-muted">(Kunde wird von der Software ignoriert)</small>
</label>
</div>

Datei anzeigen

@@ -5,10 +5,10 @@
{% macro sortable_header(label, field, current_sort, current_order) %}
<th>
{% if current_sort == field %}
<a href="{{ url_for('customers.customers', sort=field, order='desc' if current_order == 'asc' else 'asc', search=search, show_test=show_test, page=1) }}"
<a href="{{ url_for('customers.customers', sort=field, order='desc' if current_order == 'asc' else 'asc', search=search, show_fake=show_fake, page=1) }}"
class="server-sortable">
{% else %}
<a href="{{ url_for('customers.customers', sort=field, order='asc', search=search, show_test=show_test, page=1) }}"
<a href="{{ url_for('customers.customers', sort=field, order='asc', search=search, show_fake=show_fake, page=1) }}"
class="server-sortable">
{% endif %}
{{ label }}
@@ -41,10 +41,10 @@
</div>
<div class="col-md-2">
<div class="form-check mt-4">
<input class="form-check-input" type="checkbox" id="show_test" name="show_test" value="true"
{% if show_test %}checked{% endif %} onchange="this.form.submit()">
<label class="form-check-label" for="show_test">
🧪 Testdaten anzeigen
<input class="form-check-input" type="checkbox" id="show_fake" name="show_fake" value="true"
{% if show_fake %}checked{% endif %} onchange="this.form.submit()">
<label class="form-check-label" for="show_fake">
🧪 Fake-Daten anzeigen
</label>
</div>
</div>
@@ -126,31 +126,31 @@
<ul class="pagination justify-content-center">
<!-- Erste Seite -->
<li class="page-item {% if page == 1 %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('customers.customers', page=1, search=search, sort=sort, order=order, show_test=show_test) }}">Erste</a>
<a class="page-link" href="{{ url_for('customers.customers', page=1, search=search, sort=sort, order=order, show_fake=show_fake) }}">Erste</a>
</li>
<!-- Vorherige Seite -->
<li class="page-item {% if page == 1 %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('customers.customers', page=page-1, search=search, sort=sort, order=order, show_test=show_test) }}"></a>
<a class="page-link" href="{{ url_for('customers.customers', page=page-1, search=search, sort=sort, order=order, show_fake=show_fake) }}"></a>
</li>
<!-- Seitenzahlen -->
{% for p in range(1, total_pages + 1) %}
{% if p >= page - 2 and p <= page + 2 %}
<li class="page-item {% if p == page %}active{% endif %}">
<a class="page-link" href="{{ url_for('customers.customers', page=p, search=search, sort=sort, order=order, show_test=show_test) }}">{{ p }}</a>
<a class="page-link" href="{{ url_for('customers.customers', page=p, search=search, sort=sort, order=order, show_fake=show_fake) }}">{{ p }}</a>
</li>
{% endif %}
{% endfor %}
<!-- Nächste Seite -->
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('customers.customers', page=page+1, search=search, sort=sort, order=order, show_test=show_test) }}"></a>
<a class="page-link" href="{{ url_for('customers.customers', page=page+1, search=search, sort=sort, order=order, show_fake=show_fake) }}"></a>
</li>
<!-- Letzte Seite -->
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('customers.customers', page=total_pages, search=search, sort=sort, order=order, show_test=show_test) }}">Letzte</a>
<a class="page-link" href="{{ url_for('customers.customers', page=total_pages, search=search, sort=sort, order=order, show_fake=show_fake) }}">Letzte</a>
</li>
</ul>
<p class="text-center text-muted">

Datei anzeigen

@@ -17,14 +17,14 @@
<i class="bi bi-download"></i> Export
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{{ url_for('export.export_customers', format='excel', include_test=request.args.get('show_test')) }}">
<li><a class="dropdown-item" href="{{ url_for('export.export_customers', format='excel', include_test=request.args.get('show_fake')) }}">
<i class="bi bi-file-earmark-excel text-success"></i> Kunden (Excel)</a></li>
<li><a class="dropdown-item" href="{{ url_for('export.export_customers', format='csv', include_test=request.args.get('show_test')) }}">
<li><a class="dropdown-item" href="{{ url_for('export.export_customers', format='csv', include_test=request.args.get('show_fake')) }}">
<i class="bi bi-file-earmark-text"></i> Kunden (CSV)</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="{{ url_for('export.export_licenses', format='excel', include_test=request.args.get('show_test')) }}">
<li><a class="dropdown-item" href="{{ url_for('export.export_licenses', format='excel', include_test=request.args.get('show_fake')) }}">
<i class="bi bi-file-earmark-excel text-success"></i> Lizenzen (Excel)</a></li>
<li><a class="dropdown-item" href="{{ url_for('export.export_licenses', format='csv', include_test=request.args.get('show_test')) }}">
<li><a class="dropdown-item" href="{{ url_for('export.export_licenses', format='csv', include_test=request.args.get('show_fake')) }}">
<i class="bi bi-file-earmark-text"></i> Lizenzen (CSV)</a></li>
</ul>
</div>
@@ -47,11 +47,11 @@
<input type="text" class="form-control mb-2" id="customerSearch"
placeholder="Kunde suchen..." autocomplete="off">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="showTestCustomers"
{% if request.args.get('show_test', 'false').lower() == 'true' %}checked{% endif %}
onchange="toggleTestCustomers()">
<label class="form-check-label" for="showTestCustomers">
<small class="text-muted">Testkunden anzeigen</small>
<input class="form-check-input" type="checkbox" id="showFakeCustomers"
{% if request.args.get('show_fake', 'false').lower() == 'true' %}checked{% endif %}
onchange="toggleFakeCustomers()">
<label class="form-check-label" for="showFakeCustomers">
<small class="text-muted">Fake-Kunden anzeigen</small>
</label>
</div>
</div>
@@ -289,7 +289,7 @@ function loadCustomerLicenses(customerId) {
});
document.querySelector(`[data-customer-id="${customerId}"]`).classList.add('active');
// URL aktualisieren ohne Reload (behalte show_test Parameter)
// URL aktualisieren ohne Reload (behalte show_fake Parameter)
const currentUrl = new URL(window.location);
currentUrl.searchParams.set('customer_id', customerId);
window.history.pushState({}, '', currentUrl.toString());
@@ -522,10 +522,10 @@ function copyToClipboard(text) {
}
// Toggle Testkunden
function toggleTestCustomers() {
const showTest = document.getElementById('showTestCustomers').checked;
function toggleFakeCustomers() {
const showTest = document.getElementById('showFakeCustomers').checked;
const currentUrl = new URL(window.location);
currentUrl.searchParams.set('show_test', showTest);
currentUrl.searchParams.set('show_fake', showTest);
window.location.href = currentUrl.toString();
}
@@ -854,12 +854,12 @@ function quarantineResource(resourceId, resourceValue) {
// Lade verfügbare Ressourcen
function loadAvailableResources(licenseId) {
// Hole show_test Parameter aus der URL
// Hole show_fake Parameter aus der URL
const urlParams = new URLSearchParams(window.location.search);
const showTest = urlParams.get('show_test') === 'true';
const showTest = urlParams.get('show_fake') === 'true';
// Lade verfügbare Domains
fetch(`/api/resources/check-availability?type=domain&count=200&show_test=${showTest}`)
fetch(`/api/resources/check-availability?type=domain&count=200&show_fake=${showTest}`)
.then(response => response.json())
.then(data => {
const select = document.getElementById('availableDomains');
@@ -880,7 +880,7 @@ function loadAvailableResources(licenseId) {
});
// Lade verfügbare IPv4s
fetch(`/api/resources/check-availability?type=ipv4&count=200&show_test=${showTest}`)
fetch(`/api/resources/check-availability?type=ipv4&count=200&show_fake=${showTest}`)
.then(response => response.json())
.then(data => {
const select = document.getElementById('availableIpv4s');
@@ -901,7 +901,7 @@ function loadAvailableResources(licenseId) {
});
// Lade verfügbare Telefonnummern
fetch(`/api/resources/check-availability?type=phone&count=200&show_test=${showTest}`)
fetch(`/api/resources/check-availability?type=phone&count=200&show_fake=${showTest}`)
.then(response => response.json())
.then(data => {
const select = document.getElementById('availablePhones');

Datei anzeigen

@@ -116,17 +116,17 @@
<p class="text-muted">Vollversionen</p>
</div>
<div class="col-6 text-center">
<h3 class="text-warning">{{ stats.test_licenses }}</h3>
<h3 class="text-warning">{{ stats.fake_licenses }}</h3>
<p class="text-muted">Testversionen</p>
</div>
</div>
{% if stats.test_data_count > 0 or stats.test_customers_count > 0 or stats.test_resources_count > 0 %}
{% if stats.fake_data_count > 0 or stats.fake_customers_count > 0 or stats.fake_resources_count > 0 %}
<div class="alert alert-info mt-3 mb-0">
<small>
<i class="fas fa-flask"></i> Testdaten:
{{ stats.test_data_count }} Lizenzen,
{{ stats.test_customers_count }} Kunden,
{{ stats.test_resources_count }} Ressourcen
<i class="fas fa-flask"></i> Fake-Daten:
{{ stats.fake_data_count }} Lizenzen,
{{ stats.fake_customers_count }} Kunden,
{{ stats.fake_resources_count }} Ressourcen
</small>
</div>
{% endif %}

Datei anzeigen

@@ -7,15 +7,15 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>Kunde bearbeiten</h2>
<div>
<a href="{{ url_for('customers.customers_licenses', show_test=request.args.get('show_test')) }}" class="btn btn-secondary">👥 Zurück zur Übersicht</a>
<a href="{{ url_for('customers.customers_licenses', show_fake=request.args.get('show_fake')) }}" class="btn btn-secondary">👥 Zurück zur Übersicht</a>
</div>
</div>
<div class="card mb-4">
<div class="card-body">
<form method="post" action="{{ url_for('customers.edit_customer', customer_id=customer.id) }}" accept-charset="UTF-8">
{% if request.args.get('show_test') == 'true' %}
<input type="hidden" name="show_test" value="true">
{% if request.args.get('show_fake') == 'true' %}
<input type="hidden" name="show_fake" value="true">
{% endif %}
<div class="row g-3">
<div class="col-md-6">
@@ -33,16 +33,16 @@
</div>
<div class="form-check mt-3">
<input class="form-check-input" type="checkbox" id="isTest" name="is_test" {% if customer.is_test %}checked{% endif %}>
<input class="form-check-input" type="checkbox" id="isTest" name="is_fake" {% if customer.is_fake %}checked{% endif %}>
<label class="form-check-label" for="isTest">
<i class="fas fa-flask"></i> Als Testdaten markieren
<i class="fas fa-flask"></i> Als Fake-Daten markieren
<small class="text-muted">(Kunde und seine Lizenzen werden von der Software ignoriert)</small>
</label>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary">💾 Änderungen speichern</button>
<a href="{{ url_for('customers.customers_licenses', show_test=request.args.get('show_test')) }}" class="btn btn-secondary">Abbrechen</a>
<a href="{{ url_for('customers.customers_licenses', show_fake=request.args.get('show_fake')) }}" class="btn btn-secondary">Abbrechen</a>
</div>
</form>
</div>

Datei anzeigen

@@ -7,15 +7,15 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>Lizenz bearbeiten</h2>
<div>
<a href="{{ url_for('customers.customers_licenses', show_test=request.args.get('show_test')) }}" class="btn btn-secondary">📋 Zurück zur Übersicht</a>
<a href="{{ url_for('customers.customers_licenses', show_fake=request.args.get('show_fake')) }}" class="btn btn-secondary">📋 Zurück zur Übersicht</a>
</div>
</div>
<div class="card">
<div class="card-body">
<form method="post" action="{{ url_for('licenses.edit_license', license_id=license.id) }}" accept-charset="UTF-8">
{% if request.args.get('show_test') == 'true' %}
<input type="hidden" name="show_test" value="true">
{% if request.args.get('show_fake') == 'true' %}
<input type="hidden" name="show_fake" value="true">
{% endif %}
<div class="row g-3">
<div class="col-md-6">
@@ -66,16 +66,16 @@
</div>
<div class="form-check mt-3">
<input class="form-check-input" type="checkbox" id="isTest" name="is_test" {% if license.is_test %}checked{% endif %}>
<input class="form-check-input" type="checkbox" id="isTest" name="is_fake" {% if license.is_fake %}checked{% endif %}>
<label class="form-check-label" for="isTest">
<i class="fas fa-flask"></i> Als Testdaten markieren
<i class="fas fa-flask"></i> Als Fake-Daten markieren
<small class="text-muted">(wird von der Software ignoriert)</small>
</label>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary">💾 Änderungen speichern</button>
<a href="{{ url_for('customers.customers_licenses', show_test=request.args.get('show_test')) }}" class="btn btn-secondary">Abbrechen</a>
<a href="{{ url_for('customers.customers_licenses', show_fake=request.args.get('show_fake')) }}" class="btn btn-secondary">Abbrechen</a>
</div>
</form>
</div>

Datei anzeigen

@@ -154,9 +154,9 @@
<!-- Test Data Checkbox -->
<div class="form-check mt-3">
<input class="form-check-input" type="checkbox" id="isTest" name="is_test">
<input class="form-check-input" type="checkbox" id="isTest" name="is_fake">
<label class="form-check-label" for="isTest">
<i class="fas fa-flask"></i> Als Testdaten markieren
<i class="fas fa-flask"></i> Als Fake-Daten markieren
<small class="text-muted">(wird von der Software ignoriert)</small>
</label>
</div>

Datei anzeigen

@@ -4,13 +4,20 @@
{% macro sortable_header(label, field, current_sort, current_order) %}
<th>
{% set base_url = url_for('licenses.licenses') %}
{% set params = [] %}
{% if search %}{% set _ = params.append('search=' + search|urlencode) %}{% endif %}
{% for type in filter_types %}{% set _ = params.append('types[]=' + type|urlencode) %}{% endfor %}
{% for status in filter_statuses %}{% set _ = params.append('statuses[]=' + status|urlencode) %}{% endfor %}
{% set _ = params.append('sort=' + field) %}
{% if current_sort == field %}
<a href="{{ url_for('licenses.licenses', sort=field, order='desc' if current_order == 'asc' else 'asc', search=search, type=filter_type, status=filter_status, page=1) }}"
class="server-sortable">
{% set _ = params.append('order=' + ('desc' if current_order == 'asc' else 'asc')) %}
{% else %}
<a href="{{ url_for('licenses.licenses', sort=field, order='asc', search=search, type=filter_type, status=filter_status, page=1) }}"
class="server-sortable">
{% set _ = params.append('order=asc') %}
{% endif %}
{% set _ = params.append('page=1') %}
<a href="{{ base_url }}?{{ params|join('&') }}" class="server-sortable">
{{ label }}
<span class="sort-indicator{% if current_sort == field %} active{% endif %}">
{% if current_sort == field %}
@@ -24,6 +31,46 @@
{% endmacro %}
{% block extra_css %}
<style>
.filter-group {
background-color: #f8f9fa;
padding: 15px;
border-radius: 8px;
margin-bottom: 15px;
}
.filter-group h6 {
color: #495057;
font-weight: 600;
}
.badge.bg-info {
background-color: #0dcaf0 !important;
font-size: 0.75rem;
}
.active-filters .badge {
font-size: 0.875rem;
padding: 0.35em 0.65em;
}
.active-filters a {
text-decoration: none;
opacity: 0.8;
}
.active-filters a:hover {
opacity: 1;
}
#advancedFilters {
transition: all 0.3s ease;
}
.btn-sm {
padding: 0.375rem 0.75rem;
}
</style>
{% endblock %}
{% block content %}
@@ -36,46 +83,162 @@
<div class="card mb-3">
<div class="card-body">
<form method="get" action="{{ url_for('licenses.licenses') }}" id="filterForm">
<div class="row g-3 align-items-end">
<div class="col-md-4">
<!-- Suchfeld -->
<div class="row g-3 mb-3">
<div class="col-md-8">
<label for="search" class="form-label">🔍 Suchen</label>
<input type="text" class="form-control" id="search" name="search"
placeholder="Lizenzschlüssel, Kunde, E-Mail..."
value="{{ search }}">
</div>
<div class="col-md-2">
<label for="type" class="form-label">Typ</label>
<select class="form-select" id="type" name="type">
<option value="">Alle Typen</option>
<option value="full" {% if filter_type == 'full' %}selected{% endif %}>Vollversion</option>
<option value="test" {% if filter_type == 'test' %}selected{% endif %}>Testversion</option>
<option value="test_data" {% if filter_type == 'test_data' %}selected{% endif %}>🧪 Testdaten</option>
<option value="live_data" {% if filter_type == 'live_data' %}selected{% endif %}>🚀 Live-Daten</option>
</select>
</div>
<div class="col-md-3">
<label for="status" class="form-label">Status</label>
<select class="form-select" id="status" name="status">
<option value="">Alle Status</option>
<option value="active" {% if filter_status == 'active' %}selected{% endif %}>✅ Aktiv</option>
<option value="expiring" {% if filter_status == 'expiring' %}selected{% endif %}>⏰ Läuft bald ab</option>
<option value="expired" {% if filter_status == 'expired' %}selected{% endif %}>⚠️ Abgelaufen</option>
<option value="inactive" {% if filter_status == 'inactive' %}selected{% endif %}>❌ Deaktiviert</option>
</select>
</div>
<div class="col-md-3">
<a href="{{ url_for('licenses.licenses') }}" class="btn btn-outline-secondary">Zurücksetzen</a>
<div class="col-md-4 text-end">
<label class="form-label d-block">&nbsp;</label>
<button type="button" class="btn btn-outline-primary me-2" onclick="toggleFilters()">
<i class="bi bi-funnel"></i> Filter
</button>
<a href="{{ url_for('licenses.licenses') }}" class="btn btn-outline-secondary">
<i class="bi bi-arrow-clockwise"></i> Zurücksetzen
</a>
</div>
</div>
<!-- Erweiterter Filterbereich -->
<div id="advancedFilters" class="collapse {{ 'show' if filter_types or filter_status else '' }}">
<hr class="my-3">
<!-- Lizenztyp Filter (OR Logic) -->
<div class="filter-group mb-3">
<div class="d-flex align-items-center mb-2">
<h6 class="mb-0 me-2">Lizenztyp</h6>
<span class="badge bg-info">ODER</span>
</div>
<div class="row g-2">
<div class="col-auto">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="types[]" value="full" id="typeFullversion"
{% if 'full' in (filter_types or []) %}checked{% endif %}>
<label class="form-check-label" for="typeFullversion">
<span class="badge bg-success">Vollversion</span>
</label>
</div>
</div>
<div class="col-auto">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="types[]" value="test" id="typeTestversion"
{% if 'test' in (filter_types or []) %}checked{% endif %}>
<label class="form-check-label" for="typeTestversion">
<span class="badge bg-warning">Testversion</span>
</label>
</div>
</div>
</div>
</div>
<!-- Status Filter (OR Logic) -->
<div class="filter-group mb-3">
<div class="d-flex align-items-center mb-2">
<h6 class="mb-0 me-2">Status</h6>
<span class="badge bg-info">ODER</span>
</div>
<div class="row g-2">
<div class="col-auto">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="statuses[]" value="active" id="statusActive"
{% if 'active' in (filter_statuses or []) %}checked{% endif %}>
<label class="form-check-label" for="statusActive">
✅ Aktiv
</label>
</div>
</div>
<div class="col-auto">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="statuses[]" value="expiring" id="statusExpiring"
{% if 'expiring' in (filter_statuses or []) %}checked{% endif %}>
<label class="form-check-label" for="statusExpiring">
⏰ Läuft bald ab
</label>
</div>
</div>
<div class="col-auto">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="statuses[]" value="expired" id="statusExpired"
{% if 'expired' in (filter_statuses or []) %}checked{% endif %}>
<label class="form-check-label" for="statusExpired">
⚠️ Abgelaufen
</label>
</div>
</div>
<div class="col-auto">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="statuses[]" value="inactive" id="statusInactive"
{% if 'inactive' in (filter_statuses or []) %}checked{% endif %}>
<label class="form-check-label" for="statusInactive">
❌ Deaktiviert
</label>
</div>
</div>
</div>
</div>
<!-- Quick Filters / Presets -->
<div class="filter-group">
<h6 class="mb-2">Schnellfilter</h6>
<div class="row g-2">
<div class="col-auto">
<button type="button" class="btn btn-sm btn-outline-primary" onclick="applyPreset('expiring_soon')">
<i class="bi bi-clock-history"></i> Läuft in 7 Tagen ab
</button>
</div>
<div class="col-auto">
<button type="button" class="btn btn-sm btn-outline-primary" onclick="applyPreset('all_test')">
<i class="bi bi-bug"></i> Alle Testversionen
</button>
</div>
<div class="col-auto">
<button type="button" class="btn btn-sm btn-outline-primary" onclick="applyPreset('active_full')">
<i class="bi bi-shield-check"></i> Aktive Vollversionen
</button>
</div>
</div>
</div>
</div>
<!-- Hidden fields for sorting -->
<input type="hidden" name="sort" value="{{ sort }}">
<input type="hidden" name="order" value="{{ order }}">
</form>
{% if search or filter_type or filter_status %}
{% if search or filter_types or filter_statuses %}
<div class="mt-2">
<small class="text-muted">
Gefiltert: {{ total }} Ergebnisse
{% if search %} | Suche: <strong>{{ search }}</strong>{% endif %}
{% if filter_type %} | Typ: <strong>{{ 'Vollversion' if filter_type == 'full' else 'Testversion' }}</strong>{% endif %}
{% if filter_status %} | Status: <strong>{{ filter_status }}</strong>{% endif %}
</small>
<div class="d-flex align-items-center justify-content-between">
<small class="text-muted">
Gefiltert: {{ total }} Ergebnisse
</small>
<div class="active-filters">
{% if search %}
<span class="badge bg-secondary me-1">
<i class="bi bi-search"></i> {{ search }}
{% set clear_search_params = [] %}
{% for type in filter_types %}{% set _ = clear_search_params.append('types[]=' + type|urlencode) %}{% endfor %}
{% for status in filter_statuses %}{% set _ = clear_search_params.append('statuses[]=' + status|urlencode) %}{% endfor %}
{% set _ = clear_search_params.append('sort=' + sort) %}
{% set _ = clear_search_params.append('order=' + order) %}
<a href="{{ url_for('licenses.licenses') }}?{{ clear_search_params|join('&') }}" class="text-white ms-1">&times;</a>
</span>
{% endif %}
{% for type in (filter_types or []) %}
<span class="badge bg-primary me-1">
{{ 'Vollversion' if type == 'full' else 'Testversion' }}
<a href="#" onclick="removeFilter('type', '{{ type }}')" class="text-white ms-1">&times;</a>
</span>
{% endfor %}
{% for status in (filter_statuses or []) %}
<span class="badge bg-info me-1">
{% if status == 'active' %}✅ Aktiv{% elif status == 'expiring' %}⏰ Läuft bald ab{% elif status == 'expired' %}⚠️ Abgelaufen{% else %}❌ Deaktiviert{% endif %}
<a href="#" onclick="removeFilter('status', '{{ status }}')" class="text-white ms-1">&times;</a>
</span>
{% endfor %}
</div>
</div>
</div>
{% endif %}
</div>
@@ -119,8 +282,8 @@
</td>
<td>
{{ license.customer_name }}
{% if license.is_test %}
<span class="badge bg-secondary ms-1" title="Testdaten">🧪</span>
{% if license.is_fake %}
<span class="badge bg-secondary ms-1" title="Fake-Daten">🧪</span>
{% endif %}
</td>
<td>-</td>
@@ -182,33 +345,41 @@
{% if total_pages > 1 %}
<nav aria-label="Seitennavigation" class="mt-3">
<ul class="pagination justify-content-center">
{% set base_url = url_for('licenses.licenses') %}
{% set base_params = [] %}
{% if search %}{% set _ = base_params.append('search=' + search|urlencode) %}{% endif %}
{% for type in filter_types %}{% set _ = base_params.append('types[]=' + type|urlencode) %}{% endfor %}
{% for status in filter_statuses %}{% set _ = base_params.append('statuses[]=' + status|urlencode) %}{% endfor %}
{% set _ = base_params.append('sort=' + sort) %}
{% set _ = base_params.append('order=' + order) %}
<!-- Erste Seite -->
<li class="page-item {% if page == 1 %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('licenses.licenses', page=1, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}">Erste</a>
<a class="page-link" href="{{ base_url }}?{{ base_params|join('&') }}&page=1">Erste</a>
</li>
<!-- Vorherige Seite -->
<li class="page-item {% if page == 1 %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('licenses.licenses', page=page-1, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}"></a>
<a class="page-link" href="{{ base_url }}?{{ base_params|join('&') }}&page={{ page-1 }}"></a>
</li>
<!-- Seitenzahlen -->
{% for p in range(1, total_pages + 1) %}
{% if p >= page - 2 and p <= page + 2 %}
<li class="page-item {% if p == page %}active{% endif %}">
<a class="page-link" href="{{ url_for('licenses.licenses', page=p, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}">{{ p }}</a>
<a class="page-link" href="{{ base_url }}?{{ base_params|join('&') }}&page={{ p }}">{{ p }}</a>
</li>
{% endif %}
{% endfor %}
<!-- Nächste Seite -->
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('licenses.licenses', page=page+1, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}"></a>
<a class="page-link" href="{{ base_url }}?{{ base_params|join('&') }}&page={{ page+1 }}"></a>
</li>
<!-- Letzte Seite -->
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('licenses.licenses', page=total_pages, search=search, type=filter_type, status=filter_status, sort=sort, order=order) }}">Letzte</a>
<a class="page-link" href="{{ base_url }}?{{ base_params|join('&') }}&page={{ total_pages }}">Letzte</a>
</li>
</ul>
<p class="text-center text-muted">
@@ -235,12 +406,58 @@
{% block extra_js %}
<script>
// Toggle Filter Panel
function toggleFilters() {
const filtersDiv = document.getElementById('advancedFilters');
const bsCollapse = new bootstrap.Collapse(filtersDiv, {
toggle: true
});
}
// Apply Preset Filters
function applyPreset(preset) {
const form = document.getElementById('filterForm');
// Clear existing filters
document.querySelectorAll('input[name="types[]"]').forEach(cb => cb.checked = false);
document.querySelectorAll('input[name="statuses[]"]').forEach(cb => cb.checked = false);
switch(preset) {
case 'expiring_soon':
document.getElementById('statusExpiring').checked = true;
break;
case 'all_test':
document.getElementById('typeTestversion').checked = true;
break;
case 'active_full':
document.getElementById('typeFullversion').checked = true;
document.getElementById('statusActive').checked = true;
break;
}
form.submit();
}
// Remove Individual Filter
function removeFilter(filterType, value) {
const form = document.getElementById('filterForm');
if (filterType === 'type') {
const checkbox = document.querySelector(`input[name="types[]"][value="${value}"]`);
if (checkbox) checkbox.checked = false;
} else if (filterType === 'status') {
const checkbox = document.querySelector(`input[name="statuses[]"][value="${value}"]`);
if (checkbox) checkbox.checked = false;
}
form.submit();
return false;
}
// Live Filtering
document.addEventListener('DOMContentLoaded', function() {
const filterForm = document.getElementById('filterForm');
const searchInput = document.getElementById('search');
const typeSelect = document.getElementById('type');
const statusSelect = document.getElementById('status');
// Debounce timer für Suchfeld
let searchTimeout;
@@ -253,13 +470,11 @@ document.addEventListener('DOMContentLoaded', function() {
}, 300);
});
// Live-Filter für Dropdowns (sofort)
typeSelect.addEventListener('change', function() {
filterForm.submit();
});
statusSelect.addEventListener('change', function() {
filterForm.submit();
// Live-Filter für Checkboxen
document.querySelectorAll('input[name="types[]"], input[name="statuses[]"]').forEach(checkbox => {
checkbox.addEventListener('change', function() {
filterForm.submit();
});
});
});

Datei anzeigen

@@ -225,7 +225,7 @@
<div class="card-body py-2">
<div class="form-check mb-0">
<input class="form-check-input" type="checkbox" id="showTestResources"
{% if show_test %}checked{% endif %}
{% if show_fake %}checked{% endif %}
onchange="toggleTestResources()">
<label class="form-check-label" for="showTestResources">
Testressourcen anzeigen
@@ -293,7 +293,7 @@
<div class="card filter-card mb-4">
<div class="card-body">
<form method="get" action="{{ url_for('resources.resources') }}" id="filterForm">
<input type="hidden" name="show_test" value="{{ 'true' if show_test else 'false' }}">
<input type="hidden" name="show_fake" value="{{ 'true' if show_fake else 'false' }}">
<div class="row g-3">
<div class="col-md-3">
<label for="type" class="form-label">🏷️ Typ</label>
@@ -320,7 +320,7 @@
</div>
<div class="col-md-2">
<label class="form-label">&nbsp;</label>
<a href="{{ url_for('resources.resources', show_test=show_test) }}" class="btn btn-secondary w-100">
<a href="{{ url_for('resources.resources', show_fake=show_fake) }}" class="btn btn-secondary w-100">
🔄 Zurücksetzen
</a>
</div>
@@ -344,7 +344,7 @@
<i class="bi bi-download"></i> Export
</button>
<ul class="dropdown-menu" aria-labelledby="exportDropdown">
<li><a class="dropdown-item" href="{{ url_for('resources.resources_report', format='excel', type=resource_type, status=status_filter, search=search, show_test=show_test) }}">
<li><a class="dropdown-item" href="{{ url_for('resources.resources_report', format='excel', type=resource_type, status=status_filter, search=search, show_fake=show_fake) }}">
<i class="bi bi-file-earmark-excel text-success"></i> Excel Export</a></li>
</ul>
</div>
@@ -359,7 +359,7 @@
<thead>
<tr>
<th width="80">
<a href="{{ url_for('resources.resources', sort='id', order='desc' if sort_by == 'id' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_test=show_test) }}"
<a href="{{ url_for('resources.resources', sort='id', order='desc' if sort_by == 'id' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_fake=show_fake) }}"
class="text-decoration-none text-dark sort-link">
ID
{% if sort_by == 'id' %}
@@ -370,7 +370,7 @@
</a>
</th>
<th width="120">
<a href="{{ url_for('resources.resources', sort='type', order='desc' if sort_by == 'type' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_test=show_test) }}"
<a href="{{ url_for('resources.resources', sort='type', order='desc' if sort_by == 'type' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_fake=show_fake) }}"
class="text-decoration-none text-dark sort-link">
Typ
{% if sort_by == 'type' %}
@@ -381,7 +381,7 @@
</a>
</th>
<th>
<a href="{{ url_for('resources.resources', sort='resource', order='desc' if sort_by == 'resource' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_test=show_test) }}"
<a href="{{ url_for('resources.resources', sort='resource', order='desc' if sort_by == 'resource' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_fake=show_fake) }}"
class="text-decoration-none text-dark sort-link">
Ressource
{% if sort_by == 'resource' %}
@@ -392,7 +392,7 @@
</a>
</th>
<th width="140">
<a href="{{ url_for('resources.resources', sort='status', order='desc' if sort_by == 'status' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_test=show_test) }}"
<a href="{{ url_for('resources.resources', sort='status', order='desc' if sort_by == 'status' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_fake=show_fake) }}"
class="text-decoration-none text-dark sort-link">
Status
{% if sort_by == 'status' %}
@@ -403,7 +403,7 @@
</a>
</th>
<th>
<a href="{{ url_for('resources.resources', sort='assigned', order='desc' if sort_by == 'assigned' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_test=show_test) }}"
<a href="{{ url_for('resources.resources', sort='assigned', order='desc' if sort_by == 'assigned' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_fake=show_fake) }}"
class="text-decoration-none text-dark sort-link">
Zugewiesen an
{% if sort_by == 'assigned' %}
@@ -414,7 +414,7 @@
</a>
</th>
<th width="180">
<a href="{{ url_for('resources.resources', sort='changed', order='desc' if sort_by == 'changed' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_test=show_test) }}"
<a href="{{ url_for('resources.resources', sort='changed', order='desc' if sort_by == 'changed' and sort_order == 'asc' else 'asc', type=resource_type, status=status_filter, search=search, show_fake=show_fake) }}"
class="text-decoration-none text-dark sort-link">
Letzte Änderung
{% if sort_by == 'changed' %}
@@ -474,13 +474,13 @@
<td>
{% if resource.customer_name %}
<div>
<a href="{{ url_for('customers.customers_licenses', show_test=show_test) }}"
<a href="{{ url_for('customers.customers_licenses', show_fake=show_fake) }}"
class="text-decoration-none">
<strong>{{ resource.customer_name }}</strong>
</a>
</div>
<div class="small text-muted">
<a href="{{ url_for('licenses.edit_license', license_id=resource.allocated_to_license) }}?ref=resources{{ '&show_test=true' if show_test else '' }}"
<a href="{{ url_for('licenses.edit_license', license_id=resource.allocated_to_license) }}?ref=resources{{ '&show_fake=true' if show_fake else '' }}"
class="text-decoration-none text-muted">
{{ resource.allocated_to_license }}
</a>
@@ -502,10 +502,10 @@
<td class="text-center">
{% if resource.status == 'quarantine' %}
<!-- Quick Action für Quarantäne -->
<form method="post" action="{{ url_for('resources.release', show_test=show_test, type=resource_type, status=status_filter, search=search) }}"
<form method="post" action="{{ url_for('resources.release', show_fake=show_fake, type=resource_type, status=status_filter, search=search) }}"
style="display: inline-block; margin-right: 5px;">
<input type="hidden" name="resource_ids" value="{{ resource.id }}">
<input type="hidden" name="show_test" value="{{ show_test }}">
<input type="hidden" name="show_fake" value="{{ show_fake }}">
<button type="submit"
class="btn btn-sm btn-success">
<i class="bi bi-check-circle"></i> Freigeben
@@ -546,7 +546,7 @@
{% if resource.allocated_to_license %}
<li>
<a class="dropdown-item"
href="{{ url_for('licenses.edit_license', license_id=resource.allocated_to_license) }}?ref=resources{{ '&show_test=true' if show_test else '' }}">
href="{{ url_for('licenses.edit_license', license_id=resource.allocated_to_license) }}?ref=resources{{ '&show_fake=true' if show_fake else '' }}">
<i class="bi bi-file-text text-primary"></i> Lizenz bearbeiten
</a>
</li>
@@ -554,7 +554,7 @@
{% if resource.id %}
<li>
<a class="dropdown-item"
href="{{ url_for('customers.customers_licenses', customer_id=resource.id, show_test=show_test) }}">
href="{{ url_for('customers.customers_licenses', customer_id=resource.id, show_fake=show_fake) }}">
<i class="bi bi-person text-primary"></i> Kunde anzeigen
</a>
</li>
@@ -562,10 +562,10 @@
{% elif resource.status == 'quarantine' %}
<!-- Aktionen für Quarantäne-Ressourcen -->
<li>
<form method="post" action="{{ url_for('resources.release', show_test=show_test, type=resource_type, status=status_filter, search=search) }}"
<form method="post" action="{{ url_for('resources.release', show_fake=show_fake, type=resource_type, status=status_filter, search=search) }}"
style="display: contents;">
<input type="hidden" name="resource_ids" value="{{ resource.id }}">
<input type="hidden" name="show_test" value="{{ show_test }}">
<input type="hidden" name="show_fake" value="{{ show_fake }}">
<button type="submit" class="dropdown-item">
<i class="bi bi-check-circle text-success"></i> Ressource freigeben
</button>
@@ -614,13 +614,13 @@
<ul class="pagination justify-content-center">
<li class="page-item {% if page == 1 %}disabled{% endif %}">
<a class="page-link"
href="{{ url_for('resources.resources', page=1, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
href="{{ url_for('resources.resources', page=1, type=resource_type, status=status_filter, search=search, show_fake=show_fake, sort=sort_by, order=sort_order) }}">
<i class="bi bi-chevron-double-left"></i> Erste
</a>
</li>
<li class="page-item {% if page == 1 %}disabled{% endif %}">
<a class="page-link"
href="{{ url_for('resources.resources', page=page-1, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
href="{{ url_for('resources.resources', page=page-1, type=resource_type, status=status_filter, search=search, show_fake=show_fake, sort=sort_by, order=sort_order) }}">
<i class="bi bi-chevron-left"></i> Zurück
</a>
</li>
@@ -629,7 +629,7 @@
{% if p == page or (p >= page - 2 and p <= page + 2) %}
<li class="page-item {% if p == page %}active{% endif %}">
<a class="page-link"
href="{{ url_for('resources.resources', page=p, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
href="{{ url_for('resources.resources', page=p, type=resource_type, status=status_filter, search=search, show_fake=show_fake, sort=sort_by, order=sort_order) }}">
{{ p }}
</a>
</li>
@@ -638,13 +638,13 @@
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
<a class="page-link"
href="{{ url_for('resources.resources', page=page+1, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
href="{{ url_for('resources.resources', page=page+1, type=resource_type, status=status_filter, search=search, show_fake=show_fake, sort=sort_by, order=sort_order) }}">
Weiter <i class="bi bi-chevron-right"></i>
</a>
</li>
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
<a class="page-link"
href="{{ url_for('resources.resources', page=total_pages, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
href="{{ url_for('resources.resources', page=total_pages, type=resource_type, status=status_filter, search=search, show_fake=show_fake, sort=sort_by, order=sort_order) }}">
Letzte <i class="bi bi-chevron-double-right"></i>
</a>
</li>
@@ -702,7 +702,7 @@
<div class="modal-content">
<form method="post" id="quarantineForm">
<!-- Filter-Parameter als Hidden Fields -->
<input type="hidden" name="show_test" value="{{ show_test }}">
<input type="hidden" name="show_fake" value="{{ show_fake }}">
<input type="hidden" name="type" value="{{ resource_type }}">
<input type="hidden" name="status" value="{{ status_filter }}">
<input type="hidden" name="search" value="{{ search }}">
@@ -852,7 +852,7 @@ function showQuarantineModal(resourceId) {
function toggleTestResources() {
const showTest = document.getElementById('showTestResources').checked;
const currentUrl = new URL(window.location);
currentUrl.searchParams.set('show_test', showTest);
currentUrl.searchParams.set('show_fake', showTest);
window.location.href = currentUrl.toString();
}