feat: Add user count, ID column, and sorting to users table
- Display total user count in the card header. - Add a new '#' column to the user table showing the row number. - Sort the user list alphabetically by username (case-insensitive) using Jinja filter before rendering. - Update JavaScript column index references (`td:eq(n)`) to reflect the added '#' column.
This commit is contained in:
@ -17,10 +17,9 @@
|
|||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3 class="card-title">User List</h3>
|
<h3 class="card-title">User List {% if users %}({{ users|length }}){% endif %}</h3>
|
||||||
<div class="card-tools d-flex align-items-center flex-wrap">
|
<div class="card-tools d-flex align-items-center flex-wrap">
|
||||||
|
|
||||||
<!-- Filter Buttons -->
|
|
||||||
<div class="mr-2 mb-2">
|
<div class="mr-2 mb-2">
|
||||||
<button type="button" class="btn btn-sm btn-default filter-button" data-filter="all">
|
<button type="button" class="btn btn-sm btn-default filter-button" data-filter="all">
|
||||||
<i class="fas fa-list"></i> All
|
<i class="fas fa-list"></i> All
|
||||||
@ -42,7 +41,6 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Search Form -->
|
|
||||||
<div class="input-group input-group-sm" style="width: 200px;">
|
<div class="input-group input-group-sm" style="width: 200px;">
|
||||||
<input type="text" id="searchInput" class="form-control float-right" placeholder="Search">
|
<input type="text" id="searchInput" class="form-control float-right" placeholder="Search">
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
@ -51,11 +49,9 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Add User Button -->
|
|
||||||
<button type="button" class="btn btn-sm btn-primary ml-2" data-toggle="modal" data-target="#addUserModal">
|
<button type="button" class="btn btn-sm btn-primary ml-2" data-toggle="modal" data-target="#addUserModal">
|
||||||
<i class="fas fa-plus"></i>
|
<i class="fas fa-plus"></i>
|
||||||
</button>
|
</button>
|
||||||
<!-- Delete Selected Button -->
|
|
||||||
<button type="button" class="btn btn-sm btn-danger ml-2" id="deleteSelected">
|
<button type="button" class="btn btn-sm btn-danger ml-2" id="deleteSelected">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
@ -73,6 +69,7 @@
|
|||||||
<th>
|
<th>
|
||||||
<input type="checkbox" id="selectAll">
|
<input type="checkbox" id="selectAll">
|
||||||
</th>
|
</th>
|
||||||
|
<th>#</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th>Username</th>
|
<th>Username</th>
|
||||||
<th>Traffic Usage</th>
|
<th>Traffic Usage</th>
|
||||||
@ -84,11 +81,12 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for user in users %}
|
{% for user in users|sort(attribute='username', case_sensitive=false) %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<input type="checkbox" class="user-checkbox" value="{{ user.username }}">
|
<input type="checkbox" class="user-checkbox" value="{{ user.username }}">
|
||||||
</td>
|
</td>
|
||||||
|
<td>{{ loop.index }}</td>
|
||||||
<td>
|
<td>
|
||||||
{% if user['status'] == "Online" %}
|
{% if user['status'] == "Online" %}
|
||||||
<i class="fas fa-circle text-success"></i> Online
|
<i class="fas fa-circle text-success"></i> Online
|
||||||
@ -293,16 +291,16 @@
|
|||||||
|
|
||||||
switch (filter) {
|
switch (filter) {
|
||||||
case "all":
|
case "all":
|
||||||
showRow = true; // Show all users
|
showRow = true;
|
||||||
break;
|
break;
|
||||||
case "not-active":
|
case "not-active":
|
||||||
showRow = $(this).find("td:eq(1) i").hasClass("text-danger");
|
showRow = $(this).find("td:eq(2) i").hasClass("text-danger");
|
||||||
break;
|
break;
|
||||||
case "enable":
|
case "enable":
|
||||||
showRow = $(this).find("td:eq(6) i").hasClass("text-success");
|
showRow = $(this).find("td:eq(7) i").hasClass("text-success");
|
||||||
break;
|
break;
|
||||||
case "disable":
|
case "disable":
|
||||||
showRow = $(this).find("td:eq(6) i").hasClass("text-danger");
|
showRow = $(this).find("td:eq(7) i").hasClass("text-danger");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,14 +309,11 @@
|
|||||||
} else {
|
} else {
|
||||||
$(this).hide();
|
$(this).hide();
|
||||||
}
|
}
|
||||||
//Deselect checkbox when is not visible after sorting
|
|
||||||
$(this).find(".user-checkbox").prop("checked", false);
|
$(this).find(".user-checkbox").prop("checked", false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Multi Delete Functionality
|
|
||||||
$("#selectAll").on("change", function () {
|
$("#selectAll").on("change", function () {
|
||||||
// Only select checkboxes in visible rows
|
|
||||||
$("#userTable tbody tr:visible .user-checkbox").prop("checked", $(this).prop("checked"));
|
$("#userTable tbody tr:visible .user-checkbox").prop("checked", $(this).prop("checked"));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -444,10 +439,9 @@
|
|||||||
$(document).on("click", ".edit-user", function () {
|
$(document).on("click", ".edit-user", function () {
|
||||||
const username = $(this).data("user");
|
const username = $(this).data("user");
|
||||||
const row = $(this).closest("tr");
|
const row = $(this).closest("tr");
|
||||||
const quota = row.find("td:eq(3)").text().trim();
|
const quota = row.find("td:eq(4)").text().trim();
|
||||||
const expiry = row.find("td:eq(4)").text().trim();
|
const expiry_days = row.find("td:eq(6)").text().trim();
|
||||||
const expiry_days = row.find("td:eq(5)").text().trim();
|
const blocked = row.find("td:eq(7) i").hasClass("text-danger");
|
||||||
const blocked = row.find("td:eq(6) i").hasClass("text-danger");
|
|
||||||
|
|
||||||
const quotaMatch = quota.match(/\/\s*([\d.]+)/);
|
const quotaMatch = quota.match(/\/\s*([\d.]+)/);
|
||||||
const quotaValue = quotaMatch ? parseFloat(quotaMatch[1]) : 0;
|
const quotaValue = quotaMatch ? parseFloat(quotaMatch[1]) : 0;
|
||||||
@ -457,6 +451,9 @@
|
|||||||
$("#editTrafficLimit").val(quotaValue);
|
$("#editTrafficLimit").val(quotaValue);
|
||||||
$("#editExpirationDays").val(expiry_days);
|
$("#editExpirationDays").val(expiry_days);
|
||||||
$("#editBlocked").prop("checked", blocked);
|
$("#editBlocked").prop("checked", blocked);
|
||||||
|
|
||||||
|
const isValid = validateUsername(username, "editUsernameError");
|
||||||
|
$("#editUserForm button[type='submit']").prop("disabled", !isValid);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#editUserForm").on("submit", function (e) {
|
$("#editUserForm").on("submit", function (e) {
|
||||||
@ -755,7 +752,7 @@
|
|||||||
const searchText = $("#searchInput").val().toLowerCase();
|
const searchText = $("#searchInput").val().toLowerCase();
|
||||||
|
|
||||||
$("#userTable tbody tr").each(function () {
|
$("#userTable tbody tr").each(function () {
|
||||||
const username = $(this).find("td:eq(2)").text().toLowerCase();
|
const username = $(this).find("td:eq(3)").text().toLowerCase();
|
||||||
if (username.includes(searchText)) {
|
if (username.includes(searchText)) {
|
||||||
$(this).show();
|
$(this).show();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user