UI- Verbesserung
Dieser Commit ist enthalten in:
@@ -3820,6 +3820,69 @@ def check_resource_availability():
|
||||
|
||||
return jsonify(availability)
|
||||
|
||||
@app.route('/api/global-search', methods=['GET'])
|
||||
@login_required
|
||||
def global_search():
|
||||
"""Global search API endpoint for searching customers and licenses"""
|
||||
query = request.args.get('q', '').strip()
|
||||
|
||||
if not query or len(query) < 2:
|
||||
return jsonify({'customers': [], 'licenses': []})
|
||||
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
|
||||
# Search pattern with wildcards
|
||||
search_pattern = f'%{query}%'
|
||||
|
||||
# Search customers
|
||||
cur.execute("""
|
||||
SELECT id, name, email, company_name
|
||||
FROM customers
|
||||
WHERE (LOWER(name) LIKE LOWER(%s)
|
||||
OR LOWER(email) LIKE LOWER(%s)
|
||||
OR LOWER(company_name) LIKE LOWER(%s))
|
||||
AND is_test = FALSE
|
||||
ORDER BY name
|
||||
LIMIT 5
|
||||
""", (search_pattern, search_pattern, search_pattern))
|
||||
|
||||
customers = []
|
||||
for row in cur.fetchall():
|
||||
customers.append({
|
||||
'id': row[0],
|
||||
'name': row[1],
|
||||
'email': row[2],
|
||||
'company_name': row[3]
|
||||
})
|
||||
|
||||
# Search licenses
|
||||
cur.execute("""
|
||||
SELECT l.id, l.license_key, c.name as customer_name
|
||||
FROM licenses l
|
||||
JOIN customers c ON l.customer_id = c.id
|
||||
WHERE LOWER(l.license_key) LIKE LOWER(%s)
|
||||
AND l.is_test = FALSE
|
||||
ORDER BY l.created_at DESC
|
||||
LIMIT 5
|
||||
""", (search_pattern,))
|
||||
|
||||
licenses = []
|
||||
for row in cur.fetchall():
|
||||
licenses.append({
|
||||
'id': row[0],
|
||||
'license_key': row[1],
|
||||
'customer_name': row[2]
|
||||
})
|
||||
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
return jsonify({
|
||||
'customers': customers,
|
||||
'licenses': licenses
|
||||
})
|
||||
|
||||
@app.route('/resources/history/<int:resource_id>')
|
||||
@login_required
|
||||
def resource_history(resource_id):
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
--status-danger: #dc3545;
|
||||
--status-inactive: #6c757d;
|
||||
--status-info: #17a2b8;
|
||||
--sidebar-width: 250px;
|
||||
--sidebar-collapsed: 60px;
|
||||
}
|
||||
|
||||
/* Status Classes - Global */
|
||||
@@ -218,6 +220,111 @@
|
||||
.sort-indicator.active {
|
||||
color: var(--bs-primary);
|
||||
}
|
||||
|
||||
/* Sidebar Navigation */
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 56px;
|
||||
left: 0;
|
||||
height: calc(100vh - 56px);
|
||||
width: var(--sidebar-width);
|
||||
background-color: #f8f9fa;
|
||||
border-right: 1px solid #dee2e6;
|
||||
overflow-y: auto;
|
||||
transition: all 0.3s;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.sidebar.collapsed {
|
||||
width: var(--sidebar-collapsed);
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
padding: 1rem;
|
||||
background-color: #e9ecef;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sidebar-nav .nav-item {
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.sidebar-nav .nav-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.75rem 1rem;
|
||||
color: #495057;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.sidebar-nav .nav-link:hover {
|
||||
background-color: #e9ecef;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.sidebar-nav .nav-link.active {
|
||||
background-color: var(--bs-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.sidebar-nav .nav-link i {
|
||||
margin-right: 0.5rem;
|
||||
font-size: 1.2rem;
|
||||
width: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .sidebar-nav .nav-link span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar-submenu {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: #f1f3f4;
|
||||
}
|
||||
|
||||
.sidebar-submenu .nav-link {
|
||||
padding-left: 2.5rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Main Content with Sidebar */
|
||||
.main-content {
|
||||
margin-left: var(--sidebar-width);
|
||||
transition: all 0.3s;
|
||||
min-height: calc(100vh - 56px);
|
||||
}
|
||||
|
||||
.main-content.expanded {
|
||||
margin-left: var(--sidebar-collapsed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Responsive Adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.sidebar {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.sidebar.show {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.main-content {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
@@ -229,7 +336,7 @@
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto">
|
||||
<!-- Navigation Links entfernt - Zugriff über Dashboard -->
|
||||
<!-- Navigation removed - access via sidebar -->
|
||||
</ul>
|
||||
<div class="d-flex align-items-center">
|
||||
<div id="session-timer" class="timer-normal me-3">
|
||||
@@ -243,7 +350,103 @@
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Sidebar Navigation -->
|
||||
<aside class="sidebar" id="sidebar">
|
||||
<ul class="sidebar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint == 'dashboard' %}active{% endif %}" href="/">
|
||||
<i class="bi bi-speedometer2"></i>
|
||||
<span>Dashboard</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint in ['customers_licenses', 'edit_customer', 'create_customer', 'edit_license', 'create_license'] %}active{% endif %}" href="/customers-licenses">
|
||||
<i class="bi bi-people"></i>
|
||||
<span>Kunden & Lizenzen</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint == 'create_customer' %}active{% endif %}" href="/customer/create">
|
||||
<i class="bi bi-person-plus"></i>
|
||||
<span>Neuer Kunde</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint == 'create_license' %}active{% endif %}" href="/create">
|
||||
<i class="bi bi-plus-circle"></i>
|
||||
<span>Neue Lizenz</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint == 'batch_licenses' %}active{% endif %}" href="/batch">
|
||||
<i class="bi bi-stack"></i>
|
||||
<span>Batch-Erstellung</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint == 'resources' %}active{% endif %}" href="/resources">
|
||||
<i class="bi bi-box-seam"></i>
|
||||
<span>Resource Pool</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint == 'add_resources' %}active{% endif %}" href="/resources/add">
|
||||
<i class="bi bi-plus-square"></i>
|
||||
<span>Ressourcen hinzufügen</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint == 'audit_log' %}active{% endif %}" href="/audit">
|
||||
<i class="bi bi-journal-text"></i>
|
||||
<span>Audit-Log</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint == 'sessions' %}active{% endif %}" href="/sessions">
|
||||
<i class="bi bi-people"></i>
|
||||
<span>Sitzungen</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint == 'backups' %}active{% endif %}" href="/backups">
|
||||
<i class="bi bi-cloud-download"></i>
|
||||
<span>Backups</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint == 'blocked_ips' %}active{% endif %}" href="/security/blocked-ips">
|
||||
<i class="bi bi-shield-lock"></i>
|
||||
<span>Sicherheit</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="sidebar-header mt-4">
|
||||
<i class="bi bi-download"></i> Export
|
||||
</div>
|
||||
<ul class="sidebar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/export/licenses?format=excel">
|
||||
<i class="bi bi-file-earmark-excel"></i>
|
||||
<span>Excel Export</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/export/licenses?format=csv">
|
||||
<i class="bi bi-file-earmark-text"></i>
|
||||
<span>CSV Export</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</aside>
|
||||
|
||||
<!-- Main Content Area -->
|
||||
<div class="main-content" id="main-content">
|
||||
<!-- Page Content -->
|
||||
<div class="container-fluid p-4">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Session Warning Modal -->
|
||||
<div id="session-warning" class="session-warning-modal" style="display: none;">
|
||||
|
||||
@@ -4,13 +4,8 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div class="mb-4">
|
||||
<h2>🔑 Batch-Lizenzen erstellen</h2>
|
||||
<div>
|
||||
<a href="/create" class="btn btn-secondary">➕ Einzellizenz</a>
|
||||
<a href="/licenses" class="btn btn-secondary">📋 Lizenzen</a>
|
||||
<a href="/customers" class="btn btn-secondary">👥 Kunden</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
|
||||
@@ -25,25 +25,8 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div class="mb-4">
|
||||
<h2>Kundenverwaltung</h2>
|
||||
<div>
|
||||
<a href="/customers-licenses" class="btn btn-success">
|
||||
<i class="bi bi-layout-split"></i> Kombinierte Ansicht
|
||||
</a>
|
||||
<a href="/customer/create" class="btn btn-primary">👤 Neuer Kunde</a>
|
||||
<a href="/create" class="btn btn-primary">➕ Neue Lizenz</a>
|
||||
<a href="/batch" class="btn btn-primary">🔑 Batch-Lizenzen</a>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-info dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
📥 Export
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="/export/customers?format=excel">📊 Excel (.xlsx)</a></li>
|
||||
<li><a class="dropdown-item" href="/export/customers?format=csv">📄 CSV (.csv)</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Suchformular -->
|
||||
|
||||
@@ -2,25 +2,11 @@
|
||||
|
||||
{% block title %}Kunden & Lizenzen - AccountForger Admin{% endblock %}
|
||||
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>👥 Kunden & Lizenzen</h2>
|
||||
<div>
|
||||
<a href="/customer/create" class="btn btn-primary">👤 Neuer Kunde</a>
|
||||
<a href="/create" class="btn btn-success">➕ Neue Lizenz</a>
|
||||
<a href="/batch" class="btn btn-primary">🔑 Batch-Lizenzen</a>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-info dropdown-toggle" data-bs-toggle="dropdown">
|
||||
📥 Export
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="/export/licenses?format=excel">📊 Excel (.xlsx)</a></li>
|
||||
<li><a class="dropdown-item" href="/export/licenses?format=csv">📄 CSV (.csv)</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<h2 class="mb-4">Kunden & Lizenzen</h2>
|
||||
|
||||
<div class="row">
|
||||
<!-- Kundenliste (Links) -->
|
||||
@@ -103,9 +89,6 @@
|
||||
<a href="/customer/edit/{{ selected_customer[0] }}?ref=customers-licenses{% if request.args.get('show_test') %}&show_test=true{% endif %}" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-pencil"></i> Bearbeiten
|
||||
</a>
|
||||
<button class="btn btn-sm btn-success" onclick="showNewLicenseModal({{ selected_customer[0] }})">
|
||||
<i class="bi bi-plus"></i> Neue Lizenz
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
{% block title %}Dashboard{% endblock %}
|
||||
|
||||
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.stat-card {
|
||||
@@ -64,16 +66,8 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1>Dashboard</h1>
|
||||
<div>
|
||||
<a href="/customers-licenses{{ '?show_test=true' if request.args.get('show_test') == 'true' else '' }}" class="btn btn-success">👥 Kunden & Lizenzen</a>
|
||||
<a href="/create{{ '?show_test=true' if request.args.get('show_test') == 'true' else '' }}" class="btn btn-primary">➕ Neue Lizenz</a>
|
||||
<a href="/resources{{ '?show_test=true' if request.args.get('show_test') == 'true' else '' }}" class="btn btn-info">📦 Resource Pool</a>
|
||||
<a href="/audit{{ '?show_test=true' if request.args.get('show_test') == 'true' else '' }}" class="btn btn-secondary">📝 Log</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<h1 class="mb-4">Dashboard</h1>
|
||||
|
||||
<!-- Statistik-Karten -->
|
||||
<div class="row g-3 mb-4">
|
||||
@@ -274,14 +268,6 @@
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="fas fa-server"></i> Resource Pool Status
|
||||
<div class="float-end">
|
||||
<a href="/resources/add{{ '?show_test=true' if request.args.get('show_test') == 'true' else '' }}" class="btn btn-sm btn-success me-1" title="Ressourcen hinzufügen">
|
||||
<i class="bi bi-plus"></i> Hinzufügen
|
||||
</a>
|
||||
<a href="/resources{{ '?show_test=true' if request.args.get('show_test') == 'true' else '' }}" class="btn btn-sm btn-light">
|
||||
Verwalten →
|
||||
</a>
|
||||
</div>
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
@@ -4,15 +4,8 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div class="mb-4">
|
||||
<h2>Neue Lizenz erstellen</h2>
|
||||
<div>
|
||||
<a href="/batch" class="btn btn-primary">🔑 Batch</a>
|
||||
<a href="/licenses" class="btn btn-secondary">📋 Lizenzen</a>
|
||||
<a href="/customers" class="btn btn-secondary">👥 Kunden</a>
|
||||
<a href="/sessions" class="btn btn-secondary">🟢 Sessions</a>
|
||||
<a href="/backups" class="btn btn-secondary">💾 Backups</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" action="/create" accept-charset="UTF-8">
|
||||
|
||||
@@ -28,24 +28,8 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div class="mb-4">
|
||||
<h2>Lizenzübersicht</h2>
|
||||
<div>
|
||||
<a href="/customers-licenses" class="btn btn-success">
|
||||
<i class="bi bi-layout-split"></i> Kombinierte Ansicht
|
||||
</a>
|
||||
<a href="/create" class="btn btn-primary">➕ Neue Lizenz</a>
|
||||
<a href="/batch" class="btn btn-primary">🔑 Batch-Lizenzen</a>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-info dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
📥 Export
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="/export/licenses?format=excel">📊 Excel (.xlsx)</a></li>
|
||||
<li><a class="dropdown-item" href="/export/licenses?format=csv">📄 CSV (.csv)</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Such- und Filterformular -->
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
{% block title %}Resource Pool{% endblock %}
|
||||
|
||||
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
/* Statistik-Karten Design wie Dashboard */
|
||||
@@ -167,30 +169,12 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid py-4">
|
||||
<div class="container-fluid">
|
||||
<!-- Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<div class="mb-4">
|
||||
<h1 class="mb-0">Resource Pool</h1>
|
||||
<p class="text-muted mb-0">Verwalten Sie Domains, IPs und Telefonnummern</p>
|
||||
</div>
|
||||
<div>
|
||||
{% if request.referrer and 'customers-licenses' in request.referrer %}
|
||||
<a href="{{ request.referrer }}" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left"></i> Zurück zu Kunden
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{{ url_for('add_resources', show_test=show_test) }}" class="btn btn-success">
|
||||
➕ Ressourcen hinzufügen
|
||||
</a>
|
||||
<a href="{{ url_for('resources_metrics', show_test=show_test) }}" class="btn btn-info">
|
||||
📊 Metriken
|
||||
</a>
|
||||
<a href="{{ url_for('resources_report', show_test=show_test) }}" class="btn btn-secondary">
|
||||
📄 Report
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Test/Live Mode Toggle -->
|
||||
<div class="card mb-3">
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren