Ressource Sort gefixt
Dieser Commit ist enthalten in:
@@ -4063,6 +4063,10 @@ def resources():
|
|||||||
status_filter = request.args.get('status', '')
|
status_filter = request.args.get('status', '')
|
||||||
search = request.args.get('search', '')
|
search = request.args.get('search', '')
|
||||||
|
|
||||||
|
# Sortierung
|
||||||
|
sort_by = request.args.get('sort', 'id')
|
||||||
|
sort_order = request.args.get('order', 'desc')
|
||||||
|
|
||||||
# Base Query
|
# Base Query
|
||||||
query = """
|
query = """
|
||||||
SELECT
|
SELECT
|
||||||
@@ -4102,8 +4106,20 @@ def resources():
|
|||||||
total = cur.fetchone()[0]
|
total = cur.fetchone()[0]
|
||||||
total_pages = (total + per_page - 1) // per_page
|
total_pages = (total + per_page - 1) // per_page
|
||||||
|
|
||||||
# Get paginated results
|
# Get paginated results with dynamic sorting
|
||||||
query += " ORDER BY rp.id DESC LIMIT %s OFFSET %s"
|
sort_column_map = {
|
||||||
|
'id': 'rp.id',
|
||||||
|
'type': 'rp.resource_type',
|
||||||
|
'resource': 'rp.resource_value',
|
||||||
|
'status': 'rp.status',
|
||||||
|
'assigned': 'c.name',
|
||||||
|
'changed': 'rp.status_changed_at'
|
||||||
|
}
|
||||||
|
|
||||||
|
sort_column = sort_column_map.get(sort_by, 'rp.id')
|
||||||
|
sort_direction = 'ASC' if sort_order == 'asc' else 'DESC'
|
||||||
|
|
||||||
|
query += f" ORDER BY {sort_column} {sort_direction} LIMIT %s OFFSET %s"
|
||||||
params.extend([per_page, offset])
|
params.extend([per_page, offset])
|
||||||
|
|
||||||
cur.execute(query, params)
|
cur.execute(query, params)
|
||||||
@@ -4123,6 +4139,8 @@ def resources():
|
|||||||
status_filter=status_filter,
|
status_filter=status_filter,
|
||||||
search=search,
|
search=search,
|
||||||
show_test=show_test,
|
show_test=show_test,
|
||||||
|
sort_by=sort_by,
|
||||||
|
sort_order=sort_order,
|
||||||
datetime=datetime,
|
datetime=datetime,
|
||||||
timedelta=timedelta)
|
timedelta=timedelta)
|
||||||
|
|
||||||
|
|||||||
@@ -192,6 +192,23 @@
|
|||||||
.btn-success {
|
.btn-success {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sortable Headers */
|
||||||
|
thead th a {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
thead th a:hover {
|
||||||
|
color: #0d6efd !important;
|
||||||
|
}
|
||||||
|
thead th a i {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -343,12 +360,72 @@
|
|||||||
<table class="table table-custom mb-0">
|
<table class="table table-custom mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th width="80">ID</th>
|
<th width="80">
|
||||||
<th width="120">Typ</th>
|
<a href="{{ url_for('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) }}"
|
||||||
<th>Ressource</th>
|
class="text-decoration-none text-dark sort-link">
|
||||||
<th width="140">Status</th>
|
ID
|
||||||
<th>Zugewiesen an</th>
|
{% if sort_by == 'id' %}
|
||||||
<th width="180">Letzte Änderung</th>
|
<i class="bi bi-caret-{{ 'up' if sort_order == 'asc' else 'down' }}-fill"></i>
|
||||||
|
{% else %}
|
||||||
|
<i class="bi bi-caret-down-fill text-muted opacity-25"></i>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<th width="120">
|
||||||
|
<a href="{{ url_for('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) }}"
|
||||||
|
class="text-decoration-none text-dark sort-link">
|
||||||
|
Typ
|
||||||
|
{% if sort_by == 'type' %}
|
||||||
|
<i class="bi bi-caret-{{ 'up' if sort_order == 'asc' else 'down' }}-fill"></i>
|
||||||
|
{% else %}
|
||||||
|
<i class="bi bi-caret-down-fill text-muted opacity-25"></i>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="{{ url_for('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) }}"
|
||||||
|
class="text-decoration-none text-dark sort-link">
|
||||||
|
Ressource
|
||||||
|
{% if sort_by == 'resource' %}
|
||||||
|
<i class="bi bi-caret-{{ 'up' if sort_order == 'asc' else 'down' }}-fill"></i>
|
||||||
|
{% else %}
|
||||||
|
<i class="bi bi-caret-down-fill text-muted opacity-25"></i>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<th width="140">
|
||||||
|
<a href="{{ url_for('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) }}"
|
||||||
|
class="text-decoration-none text-dark sort-link">
|
||||||
|
Status
|
||||||
|
{% if sort_by == 'status' %}
|
||||||
|
<i class="bi bi-caret-{{ 'up' if sort_order == 'asc' else 'down' }}-fill"></i>
|
||||||
|
{% else %}
|
||||||
|
<i class="bi bi-caret-down-fill text-muted opacity-25"></i>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="{{ url_for('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) }}"
|
||||||
|
class="text-decoration-none text-dark sort-link">
|
||||||
|
Zugewiesen an
|
||||||
|
{% if sort_by == 'assigned' %}
|
||||||
|
<i class="bi bi-caret-{{ 'up' if sort_order == 'asc' else 'down' }}-fill"></i>
|
||||||
|
{% else %}
|
||||||
|
<i class="bi bi-caret-down-fill text-muted opacity-25"></i>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<th width="180">
|
||||||
|
<a href="{{ url_for('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) }}"
|
||||||
|
class="text-decoration-none text-dark sort-link">
|
||||||
|
Letzte Änderung
|
||||||
|
{% if sort_by == 'changed' %}
|
||||||
|
<i class="bi bi-caret-{{ 'up' if sort_order == 'asc' else 'down' }}-fill"></i>
|
||||||
|
{% else %}
|
||||||
|
<i class="bi bi-caret-down-fill text-muted opacity-25"></i>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
<th width="200" class="text-center">Aktionen</th>
|
<th width="200" class="text-center">Aktionen</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -539,13 +616,13 @@
|
|||||||
<ul class="pagination justify-content-center">
|
<ul class="pagination justify-content-center">
|
||||||
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
||||||
<a class="page-link"
|
<a class="page-link"
|
||||||
href="{{ url_for('resources', page=1, type=resource_type, status=status_filter, search=search, show_test=show_test) }}">
|
href="{{ url_for('resources', page=1, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
|
||||||
<i class="bi bi-chevron-double-left"></i> Erste
|
<i class="bi bi-chevron-double-left"></i> Erste
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
||||||
<a class="page-link"
|
<a class="page-link"
|
||||||
href="{{ url_for('resources', page=page-1, type=resource_type, status=status_filter, search=search, show_test=show_test) }}">
|
href="{{ url_for('resources', page=page-1, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
|
||||||
<i class="bi bi-chevron-left"></i> Zurück
|
<i class="bi bi-chevron-left"></i> Zurück
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -554,7 +631,7 @@
|
|||||||
{% if p == page or (p >= page - 2 and p <= page + 2) %}
|
{% if p == page or (p >= page - 2 and p <= page + 2) %}
|
||||||
<li class="page-item {% if p == page %}active{% endif %}">
|
<li class="page-item {% if p == page %}active{% endif %}">
|
||||||
<a class="page-link"
|
<a class="page-link"
|
||||||
href="{{ url_for('resources', page=p, type=resource_type, status=status_filter, search=search, show_test=show_test) }}">
|
href="{{ url_for('resources', page=p, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
|
||||||
{{ p }}
|
{{ p }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -563,13 +640,13 @@
|
|||||||
|
|
||||||
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
||||||
<a class="page-link"
|
<a class="page-link"
|
||||||
href="{{ url_for('resources', page=page+1, type=resource_type, status=status_filter, search=search, show_test=show_test) }}">
|
href="{{ url_for('resources', page=page+1, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
|
||||||
Weiter <i class="bi bi-chevron-right"></i>
|
Weiter <i class="bi bi-chevron-right"></i>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
|
||||||
<a class="page-link"
|
<a class="page-link"
|
||||||
href="{{ url_for('resources', page=total_pages, type=resource_type, status=status_filter, search=search, show_test=show_test) }}">
|
href="{{ url_for('resources', page=total_pages, type=resource_type, status=status_filter, search=search, show_test=show_test, sort=sort_by, order=sort_order) }}">
|
||||||
Letzte <i class="bi bi-chevron-double-right"></i>
|
Letzte <i class="bi bi-chevron-double-right"></i>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -680,6 +757,21 @@ if (typeof bootstrap !== 'undefined') {
|
|||||||
console.log('Bootstrap version:', bootstrap.Dropdown.VERSION);
|
console.log('Bootstrap version:', bootstrap.Dropdown.VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scroll-Position speichern und wiederherstellen
|
||||||
|
(function() {
|
||||||
|
// Speichere Scroll-Position vor dem Verlassen der Seite
|
||||||
|
window.addEventListener('beforeunload', function() {
|
||||||
|
sessionStorage.setItem('resourcesScrollPos', window.scrollY);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Stelle Scroll-Position wieder her
|
||||||
|
const scrollPos = sessionStorage.getItem('resourcesScrollPos');
|
||||||
|
if (scrollPos) {
|
||||||
|
window.scrollTo(0, parseInt(scrollPos));
|
||||||
|
sessionStorage.removeItem('resourcesScrollPos');
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
// Live-Filtering
|
// Live-Filtering
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
const form = document.getElementById('filterForm');
|
const form = document.getElementById('filterForm');
|
||||||
@@ -719,6 +811,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
dropdown.toggle();
|
dropdown.toggle();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort-Links: Scroll-Position speichern
|
||||||
|
document.querySelectorAll('.sort-link').forEach(link => {
|
||||||
|
link.addEventListener('click', function(e) {
|
||||||
|
sessionStorage.setItem('resourcesScrollPos', window.scrollY);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Copy to Clipboard mit besserem Feedback
|
// Copy to Clipboard mit besserem Feedback
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren