Add UI enhancements and new features
Keyboard Navigation: - Add J/K keys for Gmail-style ticket list navigation - Add N key for new ticket, C for comment focus - Add G then D for go to dashboard (vim-style) - Add 1-4 number keys for quick status changes on ticket page - Add Enter to open selected ticket - Update keyboard help modal with all new shortcuts Ticket Age Indicator: - Show "Last activity: X days ago" on ticket view - Visual warning (yellow pulse) for tickets idle >5 days - Critical warning (red pulse) for tickets idle >10 days Ticket Clone Feature: - Add "Clone" button on ticket view - Creates copy with [CLONE] prefix in title - Preserves description, priority, category, type, visibility - Automatically creates "relates_to" dependency to original Active Filter Badges: - Show visual badges above ticket table for active filters - Click X on badge to remove individual filter - "Clear All" button to reset all filters - Color-coded by filter type (status, priority, search) Visual Enhancements: - Add keyboard-selected row highlighting for J/K navigation - Smooth animations for filter badges Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -203,10 +203,76 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
case 'open-settings-modal':
|
||||
if (typeof openSettingsModal === 'function') openSettingsModal();
|
||||
break;
|
||||
// Filter badge actions
|
||||
case 'remove-filter':
|
||||
removeFilter(target.dataset.filterType, target.dataset.filterValue);
|
||||
break;
|
||||
case 'clear-all-filters':
|
||||
clearAllFilters();
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Remove a single filter and reload page
|
||||
*/
|
||||
function removeFilter(filterType, filterValue) {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
|
||||
if (filterType === 'status') {
|
||||
const currentStatuses = (params.get('status') || '').split(',').filter(s => s.trim());
|
||||
const newStatuses = currentStatuses.filter(s => s !== filterValue);
|
||||
if (newStatuses.length > 0) {
|
||||
params.set('status', newStatuses.join(','));
|
||||
} else {
|
||||
params.delete('status');
|
||||
}
|
||||
} else if (filterType === 'priority') {
|
||||
const currentPriorities = (params.get('priority') || '').split(',').filter(p => p.trim());
|
||||
const newPriorities = currentPriorities.filter(p => p !== filterValue);
|
||||
if (newPriorities.length > 0) {
|
||||
params.set('priority', newPriorities.join(','));
|
||||
} else {
|
||||
params.delete('priority');
|
||||
}
|
||||
} else if (filterType === 'search') {
|
||||
params.delete('search');
|
||||
} else {
|
||||
params.delete(filterType);
|
||||
}
|
||||
|
||||
// Reset to page 1 when changing filters
|
||||
params.delete('page');
|
||||
|
||||
window.location.search = params.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all filters and reload page
|
||||
*/
|
||||
function clearAllFilters() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
|
||||
// Remove all filter parameters
|
||||
params.delete('status');
|
||||
params.delete('priority');
|
||||
params.delete('category');
|
||||
params.delete('type');
|
||||
params.delete('assigned_to');
|
||||
params.delete('search');
|
||||
params.delete('date_from');
|
||||
params.delete('date_to');
|
||||
params.delete('page');
|
||||
|
||||
// Keep sort parameters
|
||||
const sortParams = new URLSearchParams();
|
||||
if (params.has('sort')) sortParams.set('sort', params.get('sort'));
|
||||
if (params.has('dir')) sortParams.set('dir', params.get('dir'));
|
||||
|
||||
window.location.search = sortParams.toString();
|
||||
}
|
||||
|
||||
function initTableSorting() {
|
||||
const tableHeaders = document.querySelectorAll('th');
|
||||
tableHeaders.forEach((header, index) => {
|
||||
|
||||
Reference in New Issue
Block a user