Wire optimistic locking, visibility audit log, full ticket export
Optimistic locking: - TicketView now includes updated_at in window.ticketData - ticket.js saveTicket() sends expected_updated_at on every save so the server can detect concurrent edits - On conflict response, shows a clear toast: "ticket was modified by someone else while you were editing — reload to see latest version" - On success, syncs window.ticketData.updated_at from server response so subsequent saves use the correct lock key - update_ticket.php now returns updated_at in success response Visibility audit log: - updateVisibility() result is now checked; on success, logs a delta entry to the audit trail with from/to visibility and groups so the timeline shows who changed visibility and when Full ticket export: - export_tickets.php now accepts format=full with a single ticket_id - Produces a JSON file containing ticket fields, flat comment list (with author, timestamps, text), and the full audit timeline - Access-controlled: respects canUserAccessTicket() before exporting - EXPORT button added to ticket toolbar linking directly to the endpoint Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+16
-5
@@ -47,18 +47,29 @@ function saveTicket() {
|
||||
}
|
||||
}
|
||||
|
||||
// Include optimistic lock timestamp so the server can detect concurrent edits
|
||||
if (window.ticketData && window.ticketData.updated_at) {
|
||||
data.expected_updated_at = window.ticketData.updated_at;
|
||||
}
|
||||
|
||||
// Use the correct API path
|
||||
lt.api.post('/api/update_ticket.php', { ticket_id: ticketId, ...data })
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
.then(resp => {
|
||||
if (resp.success) {
|
||||
const statusDisplay = document.getElementById('statusDisplay');
|
||||
if (statusDisplay) {
|
||||
statusDisplay.className = `status-${data.status}`;
|
||||
statusDisplay.textContent = data.status;
|
||||
statusDisplay.className = `status-${resp.status}`;
|
||||
statusDisplay.textContent = resp.status;
|
||||
}
|
||||
// Keep local updated_at in sync so the next save uses the right lock key
|
||||
if (resp.updated_at && window.ticketData) {
|
||||
window.ticketData.updated_at = resp.updated_at;
|
||||
}
|
||||
lt.toast.success('Ticket updated successfully');
|
||||
} else if (resp.conflict) {
|
||||
lt.toast.error('This ticket was modified by someone else while you were editing. Reload to see the latest version.', 8000);
|
||||
} else {
|
||||
lt.toast.error('Error saving ticket: ' + (data.error || 'Unknown error'));
|
||||
lt.toast.error('Error saving ticket: ' + (resp.error || 'Unknown error'));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
Reference in New Issue
Block a user