Bulk actions update

This commit is contained in:
2026-01-08 23:30:25 -05:00
parent 61e3bd69ff
commit 2e7956ce40
4 changed files with 203 additions and 2 deletions

View File

@@ -2424,13 +2424,14 @@ body.dark-mode select option {
box-shadow: 0 0 30px rgba(0, 255, 65, 0.5); box-shadow: 0 0 30px rgba(0, 255, 65, 0.5);
max-width: 800px; max-width: 800px;
width: 100%; width: 100%;
max-height: 85vh; max-height: calc(90vh - 2rem);
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
font-family: var(--font-mono); font-family: var(--font-mono);
padding: 2rem; padding: 2rem;
animation: settingsSlideIn 0.3s ease; animation: settingsSlideIn 0.3s ease;
margin: auto; margin: auto;
box-sizing: border-box;
} }
@keyframes settingsSlideIn { @keyframes settingsSlideIn {

View File

@@ -742,3 +742,172 @@ document.addEventListener('DOMContentLoaded', function() {
}); });
}); });
}); });
// Bulk Status Change
function showBulkStatusModal() {
const ticketIds = getSelectedTicketIds();
if (ticketIds.length === 0) {
alert('No tickets selected');
return;
}
const modalHtml = `
<div class="modal-overlay" id="bulkStatusModal">
<div class="modal-content ascii-frame-outer">
<span class="bottom-left-corner">╚</span>
<span class="bottom-right-corner">╝</span>
<div class="ascii-section-header">Change Status for ${ticketIds.length} Ticket(s)</div>
<div class="ascii-content">
<div class="ascii-frame-inner">
<div class="modal-body">
<label for="bulkStatus">New Status:</label>
<select id="bulkStatus" class="editable">
<option value="">Select Status...</option>
<option value="Open">Open</option>
<option value="Pending">Pending</option>
<option value="In Progress">In Progress</option>
<option value="Closed">Closed</option>
</select>
</div>
</div>
</div>
<div class="ascii-divider"></div>
<div class="ascii-content">
<div class="modal-footer">
<button onclick="performBulkStatusChange()" class="btn btn-bulk">Update</button>
<button onclick="closeBulkStatusModal()" class="btn btn-secondary">Cancel</button>
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', modalHtml);
}
function closeBulkStatusModal() {
const modal = document.getElementById('bulkStatusModal');
if (modal) {
modal.remove();
}
}
function performBulkStatusChange() {
const status = document.getElementById('bulkStatus').value;
const ticketIds = getSelectedTicketIds();
if (!status) {
alert('Please select a status');
return;
}
fetch('/api/bulk_operation.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
operation_type: 'bulk_status',
ticket_ids: ticketIds,
parameters: { status: status }
})
})
.then(response => response.json())
.then(data => {
closeBulkStatusModal();
if (data.success) {
window.location.reload();
} else {
alert('Error: ' + (data.error || 'Unknown error'));
}
})
.catch(error => {
console.error('Error performing bulk status change:', error);
alert('Error performing bulk status change: ' + error.message);
});
}
// Bulk Delete
function showBulkDeleteModal() {
const ticketIds = getSelectedTicketIds();
if (ticketIds.length === 0) {
alert('No tickets selected');
return;
}
const modalHtml = `
<div class="modal-overlay" id="bulkDeleteModal">
<div class="modal-content ascii-frame-outer">
<span class="bottom-left-corner">╚</span>
<span class="bottom-right-corner">╝</span>
<div class="ascii-section-header" style="color: var(--status-closed);">⚠ Delete ${ticketIds.length} Ticket(s)</div>
<div class="ascii-content">
<div class="ascii-frame-inner">
<div class="modal-body" style="text-align: center; padding: 2rem;">
<p style="color: var(--terminal-amber); font-size: 1.1rem; margin-bottom: 1rem;">
This action cannot be undone!
</p>
<p style="color: var(--terminal-green);">
You are about to permanently delete ${ticketIds.length} ticket(s).<br>
All associated comments and history will be lost.
</p>
</div>
</div>
</div>
<div class="ascii-divider"></div>
<div class="ascii-content">
<div class="modal-footer">
<button onclick="performBulkDelete()" class="btn btn-bulk" style="background: var(--status-closed); border-color: var(--status-closed);">Delete Permanently</button>
<button onclick="closeBulkDeleteModal()" class="btn btn-secondary">Cancel</button>
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', modalHtml);
}
function closeBulkDeleteModal() {
const modal = document.getElementById('bulkDeleteModal');
if (modal) {
modal.remove();
}
}
function performBulkDelete() {
const ticketIds = getSelectedTicketIds();
fetch('/api/bulk_operation.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
operation_type: 'bulk_delete',
ticket_ids: ticketIds
})
})
.then(response => response.json())
.then(data => {
closeBulkDeleteModal();
if (data.success) {
if (typeof toast !== 'undefined') {
toast.success(`Successfully deleted ${ticketIds.length} ticket(s)`);
}
setTimeout(() => window.location.reload(), 1000);
} else {
alert('Error: ' + (data.error || 'Unknown error'));
}
})
.catch(error => {
console.error('Error performing bulk delete:', error);
alert('Error performing bulk delete: ' + error.message);
});
}

View File

@@ -128,6 +128,36 @@ class BulkOperationsModel {
} }
} }
break; break;
case 'bulk_status':
if (isset($parameters['status'])) {
$currentTicket = $ticketModel->getTicketById($ticketId);
if ($currentTicket) {
$success = $ticketModel->updateTicket([
'ticket_id' => $ticketId,
'title' => $currentTicket['title'],
'description' => $currentTicket['description'],
'category' => $currentTicket['category'],
'type' => $currentTicket['type'],
'status' => $parameters['status'],
'priority' => $currentTicket['priority']
], $operation['performed_by']);
if ($success) {
$auditLogModel->log($operation['performed_by'], 'update', 'ticket', $ticketId,
['status' => $parameters['status'], 'bulk_operation_id' => $operationId]);
}
}
}
break;
case 'bulk_delete':
$success = $ticketModel->deleteTicket($ticketId);
if ($success) {
$auditLogModel->log($operation['performed_by'], 'delete', 'ticket', $ticketId,
['bulk_operation_id' => $operationId]);
}
break;
} }
if ($success) { if ($success) {

View File

@@ -259,9 +259,10 @@
<?php if ($GLOBALS['currentUser']['is_admin'] ?? false): ?> <?php if ($GLOBALS['currentUser']['is_admin'] ?? false): ?>
<div class="bulk-actions-inline" style="display: none;"> <div class="bulk-actions-inline" style="display: none;">
<span id="selected-count">0</span> tickets selected <span id="selected-count">0</span> tickets selected
<button onclick="bulkClose()" class="btn btn-bulk">Close</button> <button onclick="showBulkStatusModal()" class="btn btn-bulk">Change Status</button>
<button onclick="showBulkAssignModal()" class="btn btn-bulk">Assign</button> <button onclick="showBulkAssignModal()" class="btn btn-bulk">Assign</button>
<button onclick="showBulkPriorityModal()" class="btn btn-bulk">Priority</button> <button onclick="showBulkPriorityModal()" class="btn btn-bulk">Priority</button>
<button onclick="showBulkDeleteModal()" class="btn btn-bulk" style="background: var(--status-closed); border-color: var(--status-closed);">Delete</button>
<button onclick="clearSelection()" class="btn btn-secondary">Clear</button> <button onclick="clearSelection()" class="btn btn-secondary">Clear</button>
</div> </div>
<?php endif; ?> <?php endif; ?>