Bulk actions update
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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; ?>
|
||||||
|
|||||||
Reference in New Issue
Block a user