fix: Resolve multiple UI and API bugs

- Remove is_active filter from get_users.php (column doesn't exist)
- Fix ticket ID validation regex in upload_attachment.php (9-digit format)
- Fix createSettingsModal reference to use openSettingsModal from settings.js
- Add error handling for dependencies tab to prevent infinite loading
- Add try-catch wrapper to ticket_dependencies.php API
- Make export dropdown visible only when tickets are selected
- Export only selected tickets instead of all filtered tickets

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-20 15:16:14 -05:00
parent be505b7312
commit bc6a5cecf8
8 changed files with 124 additions and 19 deletions

View File

@@ -3149,7 +3149,8 @@ tr:hover .quick-actions {
box-shadow: 0 0 10px rgba(0, 255, 65, 0.3);
}
.export-dropdown:hover .export-dropdown-content {
.export-dropdown:hover .export-dropdown-content,
.export-dropdown.open .export-dropdown-content {
display: block;
}

View File

@@ -117,7 +117,10 @@ function initSettingsModal() {
if (settingsIcon) {
settingsIcon.addEventListener('click', function(e) {
e.preventDefault();
createSettingsModal();
// openSettingsModal is defined in settings.js
if (typeof openSettingsModal === 'function') {
openSettingsModal();
}
});
}
}
@@ -482,6 +485,8 @@ function updateSelectionCount() {
const count = checkboxes.length;
const toolbar = document.querySelector('.bulk-actions-inline');
const countDisplay = document.getElementById('selected-count');
const exportDropdown = document.getElementById('exportDropdown');
const exportCount = document.getElementById('exportCount');
if (toolbar && countDisplay) {
if (count > 0) {
@@ -491,6 +496,16 @@ function updateSelectionCount() {
toolbar.style.display = 'none';
}
}
// Show/hide export dropdown based on selection
if (exportDropdown) {
if (count > 0) {
exportDropdown.style.display = '';
if (exportCount) exportCount.textContent = count;
} else {
exportDropdown.style.display = 'none';
}
}
}
function getSelectedTicketIds() {
@@ -1339,3 +1354,47 @@ function performQuickAssign(ticketId) {
toast.error('Error updating assignment', 4000);
});
}
/**
* Toggle export dropdown menu
*/
function toggleExportMenu(event) {
event.stopPropagation();
const dropdown = document.getElementById('exportDropdown');
const content = document.getElementById('exportDropdownContent');
if (dropdown && content) {
dropdown.classList.toggle('open');
}
}
// Close export dropdown when clicking outside
document.addEventListener('click', function(event) {
const dropdown = document.getElementById('exportDropdown');
if (dropdown && !dropdown.contains(event.target)) {
dropdown.classList.remove('open');
}
});
/**
* Export selected tickets to CSV or JSON
*/
function exportSelectedTickets(format) {
const ticketIds = getSelectedTicketIds();
if (ticketIds.length === 0) {
toast.warning('No tickets selected', 2000);
return;
}
// Build URL with selected ticket IDs
const params = new URLSearchParams();
params.set('format', format);
params.set('ticket_ids', ticketIds.join(','));
// Trigger download
window.location.href = '/api/export_tickets.php?' + params.toString();
// Close dropdown
const dropdown = document.getElementById('exportDropdown');
if (dropdown) dropdown.classList.remove('open');
}

View File

@@ -579,20 +579,39 @@ function loadDependencies() {
const ticketId = window.ticketData.id;
fetch(`/api/ticket_dependencies.php?ticket_id=${ticketId}`)
.then(response => response.json())
.then(response => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
})
.then(data => {
if (data.success) {
renderDependencies(data.dependencies);
renderDependents(data.dependents);
} else {
console.error('Error loading dependencies:', data.error);
showDependencyError(data.error || 'Failed to load dependencies');
}
})
.catch(error => {
console.error('Error loading dependencies:', error);
showDependencyError('Failed to load dependencies. The feature may not be available.');
});
}
function showDependencyError(message) {
const dependenciesList = document.getElementById('dependenciesList');
const dependentsList = document.getElementById('dependentsList');
if (dependenciesList) {
dependenciesList.innerHTML = `<p style="color: var(--terminal-amber);">${escapeHtml(message)}</p>`;
}
if (dependentsList) {
dependentsList.innerHTML = `<p style="color: var(--terminal-amber);">${escapeHtml(message)}</p>`;
}
}
function renderDependencies(dependencies) {
const container = document.getElementById('dependenciesList');
if (!container) return;