feat: complete assessment tasks
This commit is contained in:
+2
-2
@@ -22,7 +22,7 @@ Route::add('/client/login', function () {
|
|||||||
|
|
||||||
$data = [];
|
$data = [];
|
||||||
|
|
||||||
if (empty($_POST['pasword']) || empty($_POST['email'])) {
|
if (empty($_POST['password']) || empty($_POST['email'])) {
|
||||||
$error = true;
|
$error = true;
|
||||||
// include_once __DIR__ . '/layout/header/Clientleft_sidebar.php';
|
// include_once __DIR__ . '/layout/header/Clientleft_sidebar.php';
|
||||||
include_once __DIR__ . '/client-login.php';
|
include_once __DIR__ . '/client-login.php';
|
||||||
@@ -41,7 +41,7 @@ Route::add('/client/login', function () {
|
|||||||
|
|
||||||
// Insert data into the database using LicenseModel
|
// Insert data into the database using LicenseModel
|
||||||
$userModel = new UserModel();
|
$userModel = new UserModel();
|
||||||
$result = $userModel->get_by_field('id', $email);
|
$result = $userModel->get_by_field('email', $email);
|
||||||
// var_dump($result);exit;
|
// var_dump($result);exit;
|
||||||
if ($result) {
|
if ($result) {
|
||||||
if (password_verify($raw_password, $result['password']) &&
|
if (password_verify($raw_password, $result['password']) &&
|
||||||
|
|||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
version: '3.8'
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
php:
|
php:
|
||||||
@@ -26,7 +26,7 @@ services:
|
|||||||
MYSQL_USER: tfu_user
|
MYSQL_USER: tfu_user
|
||||||
MYSQL_PASSWORD: tfu_password
|
MYSQL_PASSWORD: tfu_password
|
||||||
ports:
|
ports:
|
||||||
- "3306:3306"
|
- "3307:3306"
|
||||||
volumes:
|
volumes:
|
||||||
- mysql_data:/var/lib/mysql
|
- mysql_data:/var/lib/mysql
|
||||||
command: --sql_mode=""
|
command: --sql_mode=""
|
||||||
@@ -42,4 +42,4 @@ services:
|
|||||||
- mysql
|
- mysql
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
mysql_data:
|
mysql_data:
|
||||||
|
|||||||
@@ -332,7 +332,7 @@ Route::add('/admin/login', function () {
|
|||||||
$_SESSION['is_logged_in'] = true;
|
$_SESSION['is_logged_in'] = true;
|
||||||
$_SESSION['role'] = $result['role'];
|
$_SESSION['role'] = $result['role'];
|
||||||
$_SESSION['user'] = $result['id'];
|
$_SESSION['user'] = $result['id'];
|
||||||
header('Location: /admin/users');
|
header('Location: /admin/accesslog');
|
||||||
} else {
|
} else {
|
||||||
$error = true;
|
$error = true;
|
||||||
include_once __DIR__ . '/login.php';
|
include_once __DIR__ . '/login.php';
|
||||||
@@ -501,27 +501,37 @@ Route::add('/admin/license', function () {
|
|||||||
check_login();
|
check_login();
|
||||||
$format = isset($_GET['format']) ? $_GET['format'] : 'json';
|
$format = isset($_GET['format']) ? $_GET['format'] : 'json';
|
||||||
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
|
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
|
||||||
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
|
$cursor_id = isset($_GET['cursor']) ? intval($_GET['cursor']) : 0;
|
||||||
$per_page = isset($_GET['size']) ? intval($_GET['size']) : 10;
|
$per_page = isset($_GET['size']) ? intval($_GET['size']) : 10;
|
||||||
$sort = isset($_GET['sort']) ? $_GET['sort'] : 'id';
|
$sort = isset($_GET['sort']) ? $_GET['sort'] : 'id';
|
||||||
$direction = isset($_GET['direction']) ? $_GET['direction'] : 'ASC';
|
$direction = isset($_GET['direction']) ? $_GET['direction'] : 'ASC';
|
||||||
$relationship_num = isset($_GET['relationship_num']) ? $_GET['relationship_num'] : '';
|
$relationship_num = isset($_GET['relationship_num']) ? $_GET['relationship_num'] : '';
|
||||||
|
$email_search = isset($_GET['email']) ? trim($_GET['email']) : '';
|
||||||
|
|
||||||
|
|
||||||
$licenseModel = new LicenseModel();
|
$licenseModel = new LicenseModel();
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'page_title' => 'License',
|
'page_title' => 'License',
|
||||||
'relationship_num' => $relationship_num
|
'relationship_num' => $relationship_num,
|
||||||
|
'email_search' => $email_search
|
||||||
];
|
];
|
||||||
|
|
||||||
$where = [];
|
$where = [];
|
||||||
|
|
||||||
if ($relationship_num != '') {
|
if ($relationship_num != '') {
|
||||||
$where['relationship_num'] = '"' . $relationship_num . '"';
|
// $where['relationship_num'] = '"' . $relationship_num . '"';
|
||||||
|
// $where[] = '"' . $relationship_num . '"';
|
||||||
|
$where[] = "relationship_num = '" . addslashes($relationship_num) . "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $licenseModel->get_paginated($page, $per_page, $where, $sort, $direction);
|
// Add fuzzy email search using LIKE
|
||||||
|
if ($email_search != '') {
|
||||||
|
$where[] = "email LIKE '%" . addslashes($email_search) . "%'";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use cursor-based pagination instead of offset-based
|
||||||
|
$result = $licenseModel->get_cursor_paginated($page, $per_page, $where, $sort, $direction, $cursor_id);
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
if ($format == 'json') {
|
if ($format == 'json') {
|
||||||
@@ -917,19 +927,28 @@ Route::add('/admin/project', function () {
|
|||||||
$per_page = isset($_GET['size']) ? intval($_GET['size']) : 15;
|
$per_page = isset($_GET['size']) ? intval($_GET['size']) : 15;
|
||||||
$sort = isset($_GET['sort']) ? $_GET['sort'] : 'id';
|
$sort = isset($_GET['sort']) ? $_GET['sort'] : 'id';
|
||||||
$direction = isset($_GET['direction']) ? $_GET['direction'] : 'ASC';
|
$direction = isset($_GET['direction']) ? $_GET['direction'] : 'ASC';
|
||||||
// $relationship_num = isset($_GET['relationship_num']) ? $_GET['relationship_num'] : '';
|
$project_search = isset($_GET['project_search']) ? $_GET['project_search'] : '';
|
||||||
|
$webhook_search = isset($_GET['webhook_search']) ? $_GET['webhook_search'] : '';
|
||||||
|
|
||||||
$projectModel = new ProjectModel();
|
$projectModel = new ProjectModel();
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'page_title' => 'Project',
|
'page_title' => 'Project',
|
||||||
|
'project_search' => $project_search,
|
||||||
|
'webhook_search' => $webhook_search
|
||||||
];
|
];
|
||||||
|
|
||||||
$where = [];
|
$where = [];
|
||||||
|
|
||||||
// if ($relationship_num != '') {
|
// Add fuzzy search for project_name
|
||||||
// $where['relationship_num'] = '"' . $relationship_num . '"';
|
if ($project_search != '') {
|
||||||
// }
|
$where[] = "project_name LIKE '%" . addslashes($project_search) . "%'";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add fuzzy search for webhook
|
||||||
|
if ($webhook_search != '') {
|
||||||
|
$where[] = "webhook LIKE '%" . addslashes($webhook_search) . "%'";
|
||||||
|
}
|
||||||
|
|
||||||
$result = $projectModel->get_paginated($page, $per_page, $where, 'id', 'DESC');
|
$result = $projectModel->get_paginated($page, $per_page, $where, 'id', 'DESC');
|
||||||
// echo json_encode($result);
|
// echo json_encode($result);
|
||||||
@@ -1379,19 +1398,42 @@ Route::add('/admin/report', function () {
|
|||||||
$sort = isset($_GET['sort']) ? $_GET['sort'] : 'id';
|
$sort = isset($_GET['sort']) ? $_GET['sort'] : 'id';
|
||||||
$direction = isset($_GET['direction']) ? $_GET['direction'] : 'ASC';
|
$direction = isset($_GET['direction']) ? $_GET['direction'] : 'ASC';
|
||||||
$date = isset($_GET['date']) ? $_GET['date'] : '';
|
$date = isset($_GET['date']) ? $_GET['date'] : '';
|
||||||
|
$start_date = isset($_GET['start_date']) ? $_GET['start_date'] : '';
|
||||||
|
$end_date = isset($_GET['end_date']) ? $_GET['end_date'] : '';
|
||||||
|
$project = isset($_GET['project']) ? $_GET['project'] : '';
|
||||||
|
|
||||||
|
|
||||||
$reportModel = new ReportModel();
|
$reportModel = new ReportModel();
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'page_title' => 'Report',
|
'page_title' => 'Report',
|
||||||
'date' => $date
|
'date' => $date,
|
||||||
|
"start_date" => $start_date,
|
||||||
|
"end_date" => $end_date,
|
||||||
|
"project" => $project
|
||||||
];
|
];
|
||||||
|
|
||||||
$where = [];
|
$where = [];
|
||||||
|
|
||||||
if ($date != '') {
|
if ($date != '' && empty($start_date) && empty($end_date)) {
|
||||||
$where['date'] = '"' . $date . '"';
|
$where['date'] = '"' . $date . '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($start_date) && !empty($end_date)) {
|
||||||
|
$where[] = "date BETWEEN '" . $start_date . "' AND '" . $end_date . "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($start_date) && empty($end_date)) {
|
||||||
|
$where[] = "date >= '" . $start_date . "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($start_date) && !empty($end_date)) {
|
||||||
|
$where[] = "date <= '" . $end_date . "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
if($project != '') {
|
||||||
|
$where[] = "project LIKE '%" . addslashes($project) . "%'";
|
||||||
|
}
|
||||||
|
|
||||||
$result = $reportModel->get_paginated($page, $per_page, $where, 'id', 'DESC');
|
$result = $reportModel->get_paginated($page, $per_page, $where, 'id', 'DESC');
|
||||||
// echo json_encode($result);
|
// echo json_encode($result);
|
||||||
@@ -1487,6 +1529,29 @@ Route::add('/admin/license/delete/([0-9]+)', function ($id) {
|
|||||||
$licenseModel->real_delete($id);
|
$licenseModel->real_delete($id);
|
||||||
header('Location: /admin/license');
|
header('Location: /admin/license');
|
||||||
}, 'get');
|
}, 'get');
|
||||||
|
|
||||||
|
Route::add('/admin/license/list/multiselect', function () {
|
||||||
|
check_login();
|
||||||
|
$licenseModel = new LicenseModel();
|
||||||
|
|
||||||
|
if (isset($_POST['delete'])) {
|
||||||
|
if (isset($_POST['selected_items']) && !empty($_POST['selected_items'])) {
|
||||||
|
$ids = explode(',', $_POST['selected_items']);
|
||||||
|
$ids = array_map('intval', $ids); // Sanitize IDs
|
||||||
|
$ids_string = implode(', ', $ids);
|
||||||
|
|
||||||
|
$licenseModel->real_delete_by_fields([
|
||||||
|
"id IN ($ids_string)"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
header('Location: /admin/license');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no valid action, redirect back
|
||||||
|
header('Location: /admin/license');
|
||||||
|
exit;
|
||||||
|
}, 'post');
|
||||||
Route::add('/admin/location/delete/([0-9]+)', function ($id) {
|
Route::add('/admin/location/delete/([0-9]+)', function ($id) {
|
||||||
check_login();
|
check_login();
|
||||||
$locationModel = new LocationModel();
|
$locationModel = new LocationModel();
|
||||||
@@ -1927,5 +1992,3 @@ include_once 'cal.php';
|
|||||||
include_once 'oauth-routes.php';
|
include_once 'oauth-routes.php';
|
||||||
|
|
||||||
Route::run('/');
|
Route::run('/');
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+205
-50
@@ -5,27 +5,67 @@
|
|||||||
color: white;
|
color: white;
|
||||||
/* White text color */
|
/* White text color */
|
||||||
}
|
}
|
||||||
|
.bulk-actions {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-radius: 5px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.bulk-actions.show {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2 class="text-left">Licenses <a class="btn btn-primary" href="/admin/license/add">Add</a></h2>
|
<h2 class="text-left">Licenses <a class="btn btn-primary" href="/admin/license/add">Add</a></h2>
|
||||||
|
|
||||||
|
<!-- Bulk Actions Form -->
|
||||||
|
<div class="bulk-actions" id="bulkActions">
|
||||||
|
<form action="/admin/license/list/multiselect" method="POST" onsubmit="return confirmBulkDelete()">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="mr-3"><strong>Selected items:</strong> <span id="selectedCount">0</span></span>
|
||||||
|
<button type="submit" name="delete" class="btn btn-danger btn-sm mr-2">
|
||||||
|
<i class="fa fa-trash"></i> Delete Selected
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-secondary btn-sm" onclick="clearSelection()">
|
||||||
|
Clear Selection
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="selected_items" id="selectedItems" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
<div class="row mt-2 mb-2">
|
<div class="row mt-2 mb-2">
|
||||||
<div class="col-md-6 col-md-offset-3">
|
<div class="col-md-10 col-md-offset-1">
|
||||||
<form action="?" method="GET">
|
<form action="?" method="GET" class="form-inline">
|
||||||
<div class="input-group">
|
<div class="input-group mr-2 mb-2">
|
||||||
<input type="text" name="relationship_num" class="form-control mr-2" placeholder="Enter Relationship #" value="<?php echo $data['relationship_num']; ?>">
|
<label class="mr-2" for="relationship_num">Relationship #</label>
|
||||||
<span class="input-group-btn">
|
<input id="relationship_num" type="text" name="relationship_num" class="form-control" placeholder="Enter Relationship #"
|
||||||
<button class="btn btn-primary" type="submit">Search</button>
|
value="<?php echo htmlspecialchars($data['relationship_num'] ?? ''); ?>">
|
||||||
</span>
|
</div>
|
||||||
</div><!-- /input-group -->
|
<div class="input-group mr-2 mb-2">
|
||||||
|
<label class="mr-2" for="email">Email</label>
|
||||||
|
<input id="email" type="text" name="email" class="form-control" placeholder="Fuzzy email search..."
|
||||||
|
value="<?php echo htmlspecialchars($data['email_search'] ?? ''); ?>">
|
||||||
|
</div>
|
||||||
|
<!-- Preserve cursor parameter when searching -->
|
||||||
|
<input type="hidden" name="cursor" value="0">
|
||||||
|
<span class="input-group-btn mb-2">
|
||||||
|
<button class="btn btn-primary mr-2" type="submit">Search</button>
|
||||||
|
<a class="btn btn-secondary" href="/admin/license">Clear</a>
|
||||||
|
</span>
|
||||||
</form>
|
</form>
|
||||||
</div><!-- /.col-md-6 -->
|
</div><!-- /.col-md-10 -->
|
||||||
</div><!-- /.row -->
|
</div><!-- /.row -->
|
||||||
<!-- Table Responsive Wrapper -->
|
<!-- Table Responsive Wrapper -->
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-hover dark-header">
|
<table class="table table-hover dark-header">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>
|
||||||
|
<input type="checkbox" id="selectAll" onchange="toggleSelectAll()">
|
||||||
|
<label for="selectAll" class="ml-1">Select All</label>
|
||||||
|
</th>
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
<th>Relationship #</th>
|
<th>Relationship #</th>
|
||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
@@ -38,6 +78,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($data['data'] as $key => $value) {
|
<?php foreach ($data['data'] as $key => $value) {
|
||||||
echo ' <tr>';
|
echo ' <tr>';
|
||||||
|
echo ' <td><input type="checkbox" class="item-checkbox" value="' . $value->id . '" onchange="updateBulkActions()"></td>';
|
||||||
echo ' <td>' . $value->id . ' <br/><a class=" text-info" href="/admin/license/edit/' . $value->id . '">edit</a> <a class="text-danger" href="/admin/license/delete/' . $value->id . '">delete</a></td>';
|
echo ' <td>' . $value->id . ' <br/><a class=" text-info" href="/admin/license/edit/' . $value->id . '">edit</a> <a class="text-danger" href="/admin/license/delete/' . $value->id . '">delete</a></td>';
|
||||||
echo ' <td>' . $value->relationship_num . ' </td>';
|
echo ' <td>' . $value->relationship_num . ' </td>';
|
||||||
echo ' <td>' . $value->email . ' </td>';
|
echo ' <td>' . $value->email . ' </td>';
|
||||||
@@ -53,49 +94,163 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
// Retrieve parameters
|
// Retrieve cursor pagination parameters
|
||||||
$total = $data['total'];
|
$total = $data['total'];
|
||||||
$currentPage = $data['page'];
|
$currentPage = $data['page'];
|
||||||
$perPage = 10;
|
$perPage = 10;
|
||||||
|
$lastId = isset($data['id']) ? $data['id'] : 0;
|
||||||
// Calculate the number of pages
|
$currentCursor = isset($_GET['cursor']) ? intval($_GET['cursor']) : 0;
|
||||||
$totalPages = ceil($total / $perPage);
|
$relationshipNum = isset($_GET['relationship_num']) ? $_GET['relationship_num'] : '';
|
||||||
|
$emailSearch = isset($_GET['email']) ? $_GET['email'] : '';
|
||||||
// Define a range of pages to show at any given time
|
|
||||||
$range = 2; // This can be adjusted as needed
|
// Build query parameters for pagination links
|
||||||
|
$queryParams = [];
|
||||||
$startPage = ($currentPage - $range) > 0 ? ($currentPage - $range) : 1;
|
if (!empty($relationshipNum)) {
|
||||||
$endPage = ($currentPage + $range) < $totalPages ? ($currentPage + $range) : $totalPages;
|
$queryParams['relationship_num'] = $relationshipNum;
|
||||||
|
}
|
||||||
|
if (!empty($emailSearch)) {
|
||||||
|
$queryParams['email'] = $emailSearch;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to build query string
|
||||||
|
function buildQueryString($params) {
|
||||||
|
return !empty($params) ? '&' . http_build_query($params) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$queryString = buildQueryString($queryParams);
|
||||||
|
|
||||||
|
// Determine if we have previous/next pages
|
||||||
|
$hasPrevious = $currentCursor > 0;
|
||||||
|
$hasNext = count($data['data']) >= $perPage; // If we got a full page, assume there might be more
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<!-- Pagination -->
|
<!-- Cursor-based Pagination -->
|
||||||
<nav aria-label="Page navigation">
|
<nav aria-label="Cursor-based page navigation">
|
||||||
<ul class="pagination">
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
<li class="ml-2">
|
<div class="pagination-info">
|
||||||
<a href="?page=1" aria-label="Previous">
|
<small class="text-muted">
|
||||||
<span aria-hidden="true">««</span>
|
Showing <?= count($data['data']) ?> items
|
||||||
</a>
|
<?php if ($total > 0): ?>
|
||||||
</li>
|
(Total: <?= $total ?> items)
|
||||||
<li class="ml-2">
|
<?php endif; ?>
|
||||||
<a href="?page=<?= ($currentPage - 1) > 0 ? $currentPage - 1 : 1 ?>" aria-label="Previous">
|
</small>
|
||||||
<span aria-hidden="true">«</span>
|
</div>
|
||||||
</a>
|
<ul class="pagination mb-0">
|
||||||
</li>
|
<?php if ($hasPrevious): ?>
|
||||||
<?php
|
<li class="page-item">
|
||||||
for ($i = $startPage; $i <= $endPage; $i++) {
|
<a class="page-link" href="?cursor=0<?= $queryString ?>" aria-label="First">
|
||||||
echo '<li class="ml-2' . ($currentPage == $i ? ' active' : '') . '"><a href="?page=' . $i . '">' . $i . '</a></li>';
|
<span aria-hidden="true">««</span>
|
||||||
}
|
<span class="sr-only">First</span>
|
||||||
?>
|
</a>
|
||||||
<li class="ml-2">
|
</li>
|
||||||
<a href="?page=<?= ($currentPage + 1) < $totalPages ? $currentPage + 1 : $totalPages ?>" aria-label="Next">
|
<li class="page-item">
|
||||||
<span aria-hidden="true">»</span>
|
<a class="page-link" href="?cursor=<?= max(0, $currentCursor - $perPage) ?><?= $queryString ?>" aria-label="Previous">
|
||||||
</a>
|
<span aria-hidden="true">«</span>
|
||||||
</li>
|
<span class="sr-only">Previous</span>
|
||||||
<li class="ml-2">
|
</a>
|
||||||
<a href="?page=<?= $totalPages ?>" aria-label="Next">
|
</li>
|
||||||
<span aria-hidden="true">»»</span>
|
<?php else: ?>
|
||||||
</a>
|
<li class="page-item disabled">
|
||||||
</li>
|
<span class="page-link">
|
||||||
</ul>
|
<span aria-hidden="true">««</span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li class="page-item disabled">
|
||||||
|
<span class="page-link">
|
||||||
|
<span aria-hidden="true">«</span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<li class="page-item active">
|
||||||
|
<span class="page-link">Current</span>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<?php if ($hasNext): ?>
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?cursor=<?= $lastId ?><?= $queryString ?>" aria-label="Next">
|
||||||
|
<span aria-hidden="true">»</span>
|
||||||
|
<span class="sr-only">Next</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<?php else: ?>
|
||||||
|
<li class="page-item disabled">
|
||||||
|
<span class="page-link">
|
||||||
|
<span aria-hidden="true">»</span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function toggleSelectAll() {
|
||||||
|
const selectAll = document.getElementById('selectAll');
|
||||||
|
const checkboxes = document.querySelectorAll('.item-checkbox');
|
||||||
|
|
||||||
|
checkboxes.forEach(checkbox => {
|
||||||
|
checkbox.checked = selectAll.checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
updateBulkActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBulkActions() {
|
||||||
|
const checkboxes = document.querySelectorAll('.item-checkbox:checked');
|
||||||
|
const bulkActions = document.getElementById('bulkActions');
|
||||||
|
const selectedCount = document.getElementById('selectedCount');
|
||||||
|
const selectedItems = document.getElementById('selectedItems');
|
||||||
|
const selectAll = document.getElementById('selectAll');
|
||||||
|
|
||||||
|
const count = checkboxes.length;
|
||||||
|
selectedCount.textContent = count;
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
bulkActions.classList.add('show');
|
||||||
|
const ids = Array.from(checkboxes).map(cb => cb.value);
|
||||||
|
selectedItems.value = ids.join(',');
|
||||||
|
} else {
|
||||||
|
bulkActions.classList.remove('show');
|
||||||
|
selectedItems.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update select all checkbox state
|
||||||
|
const allCheckboxes = document.querySelectorAll('.item-checkbox');
|
||||||
|
const checkedCheckboxes = document.querySelectorAll('.item-checkbox:checked');
|
||||||
|
|
||||||
|
if (checkedCheckboxes.length === 0) {
|
||||||
|
selectAll.indeterminate = false;
|
||||||
|
selectAll.checked = false;
|
||||||
|
} else if (checkedCheckboxes.length === allCheckboxes.length) {
|
||||||
|
selectAll.indeterminate = false;
|
||||||
|
selectAll.checked = true;
|
||||||
|
} else {
|
||||||
|
selectAll.indeterminate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearSelection() {
|
||||||
|
const checkboxes = document.querySelectorAll('.item-checkbox');
|
||||||
|
const selectAll = document.getElementById('selectAll');
|
||||||
|
|
||||||
|
checkboxes.forEach(checkbox => {
|
||||||
|
checkbox.checked = false;
|
||||||
|
});
|
||||||
|
selectAll.checked = false;
|
||||||
|
selectAll.indeterminate = false;
|
||||||
|
|
||||||
|
updateBulkActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmBulkDelete() {
|
||||||
|
const count = document.querySelectorAll('.item-checkbox:checked').length;
|
||||||
|
if (count === 0) {
|
||||||
|
alert('Please select at least one item to delete.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return confirm(`Are you sure you want to delete ${count} selected license(s)? This action cannot be undone.`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -540,7 +540,7 @@ class MySqlDatabaseService
|
|||||||
|
|
||||||
foreach ($parameters as $key => $value) {
|
foreach ($parameters as $key => $value) {
|
||||||
if (is_string($value) && strlen($value) > 0) {
|
if (is_string($value) && strlen($value) > 0) {
|
||||||
$sql[] = "$key";
|
$sql[] = "$value";
|
||||||
} else {
|
} else {
|
||||||
$sql[] = "$key = $value";
|
$sql[] = "$key = $value";
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-6
@@ -15,6 +15,28 @@
|
|||||||
</div>
|
</div>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
|
||||||
|
<!-- Search Form -->
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<form method="GET" action="/<?php echo $_SESSION['role'] ?>/project" class="form-inline">
|
||||||
|
<div class="form-group mr-3">
|
||||||
|
<label for="project_search" class="mr-2">Project Name:</label>
|
||||||
|
<input type="text" class="form-control" id="project_search" name="project_search"
|
||||||
|
value="<?php echo htmlspecialchars($data['project_search'] ?? ''); ?>"
|
||||||
|
placeholder="Search project name...">
|
||||||
|
</div>
|
||||||
|
<div class="form-group mr-3">
|
||||||
|
<label for="webhook_search" class="mr-2">Webhook:</label>
|
||||||
|
<input type="text" class="form-control" id="webhook_search" name="webhook_search"
|
||||||
|
value="<?php echo htmlspecialchars($data['webhook_search'] ?? ''); ?>"
|
||||||
|
placeholder="Search webhook...">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary mr-2">Search</button>
|
||||||
|
<a href="/<?php echo $_SESSION['role'] ?>/project" class="btn btn-secondary">Clear</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Table Responsive Wrapper -->
|
<!-- Table Responsive Wrapper -->
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<form id="multiselect-form" action="/<?php echo $_SESSION['role'] ?>/project/list/multiselect" method="POST">
|
<form id="multiselect-form" action="/<?php echo $_SESSION['role'] ?>/project/list/multiselect" method="POST">
|
||||||
@@ -120,28 +142,39 @@
|
|||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
<nav aria-label="Page navigation">
|
<nav aria-label="Page navigation">
|
||||||
<ul class="pagination">
|
<ul class="pagination">
|
||||||
|
<?php
|
||||||
|
// Build query string for pagination links
|
||||||
|
$queryParams = [];
|
||||||
|
if (!empty($data['project_search'])) {
|
||||||
|
$queryParams['project_search'] = $data['project_search'];
|
||||||
|
}
|
||||||
|
if (!empty($data['webhook_search'])) {
|
||||||
|
$queryParams['webhook_search'] = $data['webhook_search'];
|
||||||
|
}
|
||||||
|
$queryString = !empty($queryParams) ? '&' . http_build_query($queryParams) : '';
|
||||||
|
?>
|
||||||
<li class="ml-2">
|
<li class="ml-2">
|
||||||
<a href="?page=1" aria-label="Previous">
|
<a href="?page=1<?= $queryString ?>" aria-label="Previous">
|
||||||
<span aria-hidden="true">««</span>
|
<span aria-hidden="true">««</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="ml-2">
|
<li class="ml-2">
|
||||||
<a href="?page=<?= ($currentPage - 1) > 0 ? $currentPage - 1 : 1 ?>" aria-label="Previous">
|
<a href="?page=<?= ($currentPage - 1) > 0 ? $currentPage - 1 : 1 ?><?= $queryString ?>" aria-label="Previous">
|
||||||
<span aria-hidden="true">«</span>
|
<span aria-hidden="true">«</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<?php
|
<?php
|
||||||
for ($i = $startPage; $i <= $endPage; $i++) {
|
for ($i = $startPage; $i <= $endPage; $i++) {
|
||||||
echo '<li class="ml-2' . ($currentPage == $i ? ' active' : '') . '"><a href="?page=' . $i . '">' . $i . '</a></li>';
|
echo '<li class="ml-2' . ($currentPage == $i ? ' active' : '') . '"><a href="?page=' . $i . $queryString . '">' . $i . '</a></li>';
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<li class="ml-2">
|
<li class="ml-2">
|
||||||
<a href="?page=<?= ($currentPage + 1) < $totalPages ? $currentPage + 1 : $totalPages ?>" aria-label="Next">
|
<a href="?page=<?= ($currentPage + 1) < $totalPages ? $currentPage + 1 : $totalPages ?><?= $queryString ?>" aria-label="Next">
|
||||||
<span aria-hidden="true">»</span>
|
<span aria-hidden="true">»</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="ml-2">
|
<li class="ml-2">
|
||||||
<a href="?page=<?= $totalPages ?>" aria-label="Next">
|
<a href="?page=<?= $totalPages ?><?= $queryString ?>" aria-label="Next">
|
||||||
<span aria-hidden="true">»»</span>
|
<span aria-hidden="true">»»</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -351,4 +384,4 @@ function authorize(element) {
|
|||||||
// return false;
|
// return false;
|
||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
+52
-15
@@ -10,16 +10,36 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<h2 class="text-left">Report <a class="btn btn-primary d-none" href="/admin/report/csv?format=csv&date=<?php echo $data['date']; ?>">Export</a></h2>
|
<h2 class="text-left">Report <a class="btn btn-primary d-none" href="/admin/report/csv?format=csv&date=<?php echo $data['date']; ?>">Export</a></h2>
|
||||||
<div class="row mt-2 mb-2">
|
<div class="row mt-2 mb-2">
|
||||||
<div class="col-md-6 col-md-offset-3">
|
<div class="col-md-10 col-md-offset-1">
|
||||||
<form action="?" method="GET">
|
<form action="?" method="GET" class="form-inline">
|
||||||
<div class="input-group">
|
<div class="input-group mr-2 mb-2">
|
||||||
<input type="date" name="date" class="form-control mr-2" placeholder="" value="<?php echo $data['date']; ?>">
|
<label class="mr-2" for="date">Date</label>
|
||||||
<span class="input-group-btn">
|
<input id="date" type="date" name="date" class="form-control" placeholder="" value="<?php echo htmlspecialchars($data['date'] ?? ''); ?>">
|
||||||
<button class="btn btn-primary" type="submit">Search</button>
|
</div>
|
||||||
</span>
|
<div class="input-group mr-2 mb-2">
|
||||||
</div><!-- /input-group -->
|
<label class="mr-2" for="start_date">Start</label>
|
||||||
|
<input id="start_date" type="date" name="start_date" class="form-control" placeholder=""
|
||||||
|
value="<?php echo htmlspecialchars($data['start_date'] ?? ''); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="input-group mr-2 mb-2">
|
||||||
|
<label class="mr-2" for="end_date">End</label>
|
||||||
|
<input id="end_date" type="date" name="end_date" class="form-control" placeholder=""
|
||||||
|
value="<?php echo htmlspecialchars($data['end_date'] ?? ''); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="input-group mr-2 mb-2">
|
||||||
|
<label class="mr-2" for="project">Project</label>
|
||||||
|
<input id="project" type="text" name="project" class="form-control" placeholder="Fuzzy project search..."
|
||||||
|
value="<?php echo htmlspecialchars($data['project'] ?? ''); ?>">
|
||||||
|
</div>
|
||||||
|
<span class="input-group-btn mb-2">
|
||||||
|
<button class="btn btn-primary mr-2" type="submit">Search</button>
|
||||||
|
<a class="btn btn-secondary" href="/admin/report">Clear</a>
|
||||||
|
</span>
|
||||||
|
<div class="text-muted small ml-2 mb-2">
|
||||||
|
Tip: If a start or end date is provided, the single Date filter is ignored.
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div><!-- /.col-md-6 -->
|
</div><!-- /.col-md-10 -->
|
||||||
</div><!-- /.row -->
|
</div><!-- /.row -->
|
||||||
<!-- Table Responsive Wrapper -->
|
<!-- Table Responsive Wrapper -->
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
@@ -96,28 +116,45 @@
|
|||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
<nav aria-label="Page navigation">
|
<nav aria-label="Page navigation">
|
||||||
<ul class="pagination">
|
<ul class="pagination">
|
||||||
|
<?php
|
||||||
|
// Preserve filters in pagination links
|
||||||
|
$queryParams = [];
|
||||||
|
if (!empty($data['date'])) {
|
||||||
|
$queryParams['date'] = $data['date'];
|
||||||
|
}
|
||||||
|
if (!empty($data['start_date'])) {
|
||||||
|
$queryParams['start_date'] = $data['start_date'];
|
||||||
|
}
|
||||||
|
if (!empty($data['end_date'])) {
|
||||||
|
$queryParams['end_date'] = $data['end_date'];
|
||||||
|
}
|
||||||
|
if (!empty($data['project'])) {
|
||||||
|
$queryParams['project'] = $data['project'];
|
||||||
|
}
|
||||||
|
$queryString = !empty($queryParams) ? '&' . http_build_query($queryParams) : '';
|
||||||
|
?>
|
||||||
<li class="ml-2">
|
<li class="ml-2">
|
||||||
<a href="?page=1" aria-label="Previous">
|
<a href="?page=1<?= $queryString ?>" aria-label="Previous">
|
||||||
<span aria-hidden="true">««</span>
|
<span aria-hidden="true">««</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="ml-2">
|
<li class="ml-2">
|
||||||
<a href="?page=<?= ($currentPage - 1) > 0 ? $currentPage - 1 : 1 ?>" aria-label="Previous">
|
<a href="?page=<?= ($currentPage - 1) > 0 ? $currentPage - 1 : 1 ?><?= $queryString ?>" aria-label="Previous">
|
||||||
<span aria-hidden="true">«</span>
|
<span aria-hidden="true">«</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<?php
|
<?php
|
||||||
for ($i = $startPage; $i <= $endPage; $i++) {
|
for ($i = $startPage; $i <= $endPage; $i++) {
|
||||||
echo '<li class="ml-2' . ($currentPage == $i ? ' active' : '') . '"><a href="?page=' . $i . '">' . $i . '</a></li>';
|
echo '<li class="ml-2' . ($currentPage == $i ? ' active' : '') . '"><a href="?page=' . $i . $queryString . '">' . $i . '</a></li>';
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<li class="ml-2">
|
<li class="ml-2">
|
||||||
<a href="?page=<?= ($currentPage + 1) < $totalPages ? $currentPage + 1 : $totalPages ?>" aria-label="Next">
|
<a href="?page=<?= ($currentPage + 1) < $totalPages ? $currentPage + 1 : $totalPages ?><?= $queryString ?>" aria-label="Next">
|
||||||
<span aria-hidden="true">»</span>
|
<span aria-hidden="true">»</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="ml-2">
|
<li class="ml-2">
|
||||||
<a href="?page=<?= $totalPages ?>" aria-label="Next">
|
<a href="?page=<?= $totalPages ?><?= $queryString ?>" aria-label="Next">
|
||||||
<span aria-hidden="true">»»</span>
|
<span aria-hidden="true">»»</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -160,4 +197,4 @@ $.ajax({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user