Commit Graph

81 Commits

Author SHA1 Message Date
3c3b9d0a61 Integrate lt.time.ago() for dashboard timestamps, update README
- Add data-ts attributes to table and card view date cells so JS can
  convert them to relative time ("2h ago") while keeping the full date
  in the title attribute for hover tooltips
- Add initRelativeTimes() in dashboard.js using lt.time.ago(); runs on
  DOMContentLoaded and refreshes every 60s so times stay current
- Fix table sort for date columns to read data-ts attribute instead of
  text content (which is now relative and not sortable as a date)
- Update README: add base.css/base.js/utils.js to project structure,
  fix ascii-banner.js description, expand keyboard shortcuts table,
  add developer notes for lt.time and boot sequence behavior

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 10:52:59 -04:00
1046537429 Move ASCII banner into boot sequence, fix remaining UI issues
- Remove collapsible ASCII banner from dashboard (was cluttering the UI)
- Show ASCII banner in the boot overlay on first session visit, above
  the boot messages, with a 400ms pause before messages begin
- Add scroll fade indicator (green-tinted gradient edges) to .table-wrapper
  so users can see when the table is horizontally scrollable
- Fix null guards for tab switcher in ticket.js (tabEl, activeBtn)
- Fix Reset → RESET uppercase in AuditLogView and UserActivityView

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 10:41:57 -04:00
f0d7b9aa61 Polish: uppercase all remaining mixed-case button text
- DashboardView.php: APPLY FILTERS, CLEAR ALL, SEARCH, CHANGE STATUS, ASSIGN, PRIORITY, CLEAR, EXPORT SELECTED
- CreateTicketView.php: CREATE TICKET, CANCEL
- ticket.js: SAVE, CANCEL, REMOVE, REPLY in dynamically-generated HTML templates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 23:14:41 -04:00
90c5b3ff71 UI/UX polish: terminal design system alignment pass
Views:
- DashboardView.php: remove hardcoded [ ] from admin-badge button (CSS adds them)
- DashboardView.php: view toggle ≡/▦ → [ = ]/[ # ] (view-btn suppresses auto-brackets)
- DashboardView.php: clear-search ✗ → [ X ] (plain text, no auto-brackets on <a>)
- DashboardView.php: remove ↓ arrow emoji from export button text
- TicketView.php: tab labels → UPPERCASE (tab-btn CSS adds [ ] around text)
- TicketView.php: Edit Ticket/Clone/Add Comment/Add → title-case → UPPERCASE
- TicketView.php: reply button ↩ → [ << ] (comment-action-btn has no auto-brackets)

JavaScript:
- dashboard.js: modal/action button text all → UPPERCASE (CONFIRM/CANCEL/SAVE/ASSIGN/UPDATE/DELETE PERMANENTLY)
- dashboard.js: null guard in loadTemplate(), toggleSelectAll()
- ticket.js: null guards in addDependency(), handleFileUpload()

CSS:
- dashboard.css: z-index 1001/1002 magic numbers → var(--z-modal)/var(--z-popover)
- ticket.css: status-select hover/focus border rgba(white) → terminal palette

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 22:50:59 -04:00
84bea80abd Fix PHP parse error and CSS/JS follow-on fixes
- DashboardView.php: fix PHP parse error on line 456/472/473/474 caused by
  escaped double-quotes {$row[\"key\"]} inside double-quoted echo strings;
  replaced with safe string concatenation . $row['key'] .
- ticket.css: fix status-select hover/focus border rgba(white) → terminal palette
- ticket.js: add null guards to addComment, togglePreview, updatePreview,
  toggleMarkdownMode, and addDependency element lookups

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 22:44:08 -04:00
27075a62ee Fix bracket buttons rendering below text + UI/security improvements
CSS fixes:
- Fix [ ] brackets appearing below button text by replacing display:inline-flex
  with display:inline-block + white-space:nowrap on .btn — removes cross-browser
  flex pseudo-element inconsistency as root cause
- Remove conflicting .btn::before ripple block (position:absolute was overriding
  bracket content positioning)
- Remove overflow:hidden from .btn which was clipping bracket content
- Fix body::after duplicate rule causing GPU layer blink (second position:fixed
  rule re-created compositor layer, overriding display:none suppression)
- Replace all transition:all with scoped property transitions in dashboard.css,
  ticket.css, base.css (prevents full CSS property evaluation on every hover)
- Convert pulse-warning/pulse-critical keyframes from box-shadow to opacity
  animation (GPU-composited, eliminates CPU repaints at 60fps)
- Fix mobile *::before/*::after blanket content:none rule — now targets only
  decorative frame glyphs, preserving button brackets and status indicators
- Remove --terminal-green-dim override that broke .lt-btn hover backgrounds

JS fixes:
- Fix all lt.lt.toast.* double-prefix instances in dashboard.js
- Add null guard before .appendChild() on bulkAssignUser select
- Replace all remaining emoji with terminal bracket notation (dashboard.js,
  ticket.js, markdown.js)
- Migrate all toast.*() shim calls to lt.toast.* across all JS files

View fixes:
- Remove hardcoded [ ] brackets from .btn buttons (CSS now adds them)
- Replace all emoji with terminal bracket notation in all views and admin views
- Add missing CSP nonces to AuditLogView.php and UserActivityView.php script tags
- Bump CSS version strings to ?v=20260319b for cache busting

Security fixes:
- update_ticket.php: add authorization check (non-admins can only edit their own
  or assigned tickets)
- add_comment.php: validate and cast ticket_id to integer with 400 response
- clone_ticket.php: fix unconditional session_start(), add ticket ID validation,
  add internal ticket access check
- bulk_operation.php: add HTTP 401/403 status codes on auth failures
- upload_attachment.php: fix missing $conn arg in AttachmentModel constructor
- assign_ticket.php: add ticket existence check and permission verification

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 22:20:43 -04:00
e756f8e0bb Fix ascii-frame-outer blink caused by JS/CSS hover conflict
JS mouseenter/mouseleave handlers were setting row.style.backgroundColor
inline, fighting with the CSS tr:hover rule. On mouseleave both fired
simultaneously causing a double repaint / blink. Removed the redundant
JS handlers — the CSS tr:hover transition already handles this cleanly.

Also removed body flicker animation from base.css (was still present
after being removed from dashboard.css).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 11:14:05 -04:00
4a838b68ca Move base.js/base.css into assets to fix auth proxy 404
/web_template/ path was being intercepted by the auth proxy at
t.lotusguild.org returning HTML instead of the actual files. Moving
base.js and base.css into /assets/js/ and /assets/css/ where static
assets are already served correctly. Updated all 10 view files and
deploy.sh accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 23:44:46 -04:00
8bb43c14db Guard lt.* calls when base.js unavailable to prevent crash
Wraps all lt.keys.initDefaults() calls in `if (window.lt)` guards across
6 view files. Adds `if (!window.lt) return` bail-out in keyboard-shortcuts.js
and `if (window.lt)` guard in settings.js DOMContentLoaded handler.

This prevents TypeError crashes when /web_template/base.js returns 404,
which was causing the admin menu click delegation to never register.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 23:34:59 -04:00
89a685a502 Integrate web_template design system and fix security/quality issues
Security fixes:
- Add HTTP method validation to delete_comment.php (block CSRF via GET)
- Remove $_GET fallback in comment deletion (was CSRF bypass vector)
- Guard session_start() with session_status() check across API files
- Escape json_encode() data attributes with htmlspecialchars in views
- Escape inline APP_TIMEZONE config values in DashboardView/TicketView
- Validate timezone param against DateTimeZone::listIdentifiers() in index.php
- Remove Database::escape() (was using real_escape_string, not safe)
- Fix AttachmentModel hardcoded connection; inject via constructor

Backend fixes:
- Fix CommentModel bind_param type for ticket_id (s→i)
- Fix buildCommentThread orphan parent guard
- Fix StatsModel JOIN→LEFT JOIN so unassigned tickets aren't excluded
- Add ticket ID validation in BulkOperationsModel before implode()
- Add duplicate key retry in TicketModel::createTicket() for race conditions
- Wrap SavedFiltersModel default filter changes in transactions
- Add null result guards in WorkflowModel query methods

Frontend JS:
- Rewrite toast.js as lt.toast shim (base.js dependency)
- Delegate escapeHtml() to lt.escHtml()
- Rewrite keyboard-shortcuts.js using lt.keys.on()
- Migrate settings.js to lt.api.* and lt.modal.open/close()
- Migrate advanced-search.js to lt.api.* and lt.modal.open/close()
- Migrate dashboard.js fetch calls to lt.api.*; update all dynamic
  modals (bulk ops, quick actions, confirm/input) to lt-modal structure
- Migrate ticket.js fetchMentionUsers to lt.api.get()
- Remove console.log/error/warn calls from JS files

Views:
- Add /web_template/base.css and base.js to all 10 view files
- Call lt.keys.initDefaults() in DashboardView, TicketView, admin views
- Migrate all modal HTML from settings-modal/settings-content to
  lt-modal-overlay/lt-modal/lt-modal-header/lt-modal-body/lt-modal-footer
- Replace style="display:none" with aria-hidden="true" on all modals
- Replace modal open/close style.display with lt.modal.open/close()
- Update modal buttons to lt-btn lt-btn-primary/lt-btn-ghost classes
- Remove manual ESC keydown handlers (replaced by lt.keys.initDefaults)
- Fix unescaped timezone values in TicketView inline script

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 23:22:24 -04:00
bcc163bc77 Audit fixes: security, dead code removal, API consolidation, JS dedup
Security:
- Fix IDOR in delete/update comment (add ticket visibility check)
- XSS defense-in-depth in DashboardView active filters
- Replace innerHTML with DOM construction in toast.js
- Remove redundant real_escape_string in check_duplicates
- Add rate limiting to get_template, download_attachment, audit_log,
  saved_filters, user_preferences endpoints

Bug fixes:
- Session timeout now reads from config instead of hardcoded 18000
- TicketController uses $GLOBALS['config'] instead of duplicate .env parsing
- Add DISCORD_WEBHOOK_URL to centralized config
- Cleanup script uses hashmap for O(1) ticket ID lookups

Dead code removal (~100 lines):
- Remove dead getTicketComments() from TicketModel (wrong bind_param type)
- Remove dead getCategories()/getTypes() from DashboardController
- Remove ~80 lines dead Discord webhook code from update_ticket API

Consolidation:
- Create api/bootstrap.php for shared API setup (auth, CSRF, rate limit)
- Convert 6 API endpoints to use bootstrap
- Extract escapeHtml/getTicketIdFromUrl into shared utils.js
- Batch save for user preferences (1 request instead of 7)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 14:50:06 -05:00
019eaf8980 Add assignment dropdown on ticket creation and fix Discord webhook URLs
- Add APP_DOMAIN config for correct Discord webhook ticket links
- Add "Assign To" dropdown on create ticket form
- Update TicketModel.createTicket() to support assigned_to field
- Update documentation for APP_DOMAIN requirement

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 10:24:00 -05:00
e8b2f670b9 Fix mobile bottom nav consistency and ticket view width
Mobile bottom nav:
- Added nav-label class to all text labels in JS
- Fixed icon sizing (20px fixed height)
- Fixed label sizing (10px for all)
- Equal width columns (25% each)
- Changed gear emoji from ⚙️ to ⚙ for consistency

Ticket view mobile:
- Removed all borders from ticket container
- Removed decorative corners on mobile
- Reduced nested padding significantly
- ascii-frame-inner now 0.75rem padding (was 1rem)
- Nested ascii-frame-inner only 0.5rem
- detail-group full-width has no padding
- Content goes edge-to-edge

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 11:59:31 -05:00
73162d9a9b Add comprehensive accessibility improvements
HTML Accessibility:
- Add ARIA roles to tab navigation (role="tablist", role="tab", role="tabpanel")
- Add aria-selected to tab buttons with JS toggle
- Add aria-controls and aria-labelledby for tab/panel relationships
- Add aria-label to emoji icon buttons (settings, reply, edit, delete)
- Add aria-pressed to view toggle buttons
- Add labels for form inputs (comment textarea, dependency inputs, file input)
- Add .sr-only utility class for screen-reader-only content

CSS Accessibility:
- Add .sr-only class (visually hidden, accessible to screen readers)

JavaScript:
- Update showTab() to toggle aria-selected on tab buttons

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 00:15:11 -05:00
3ceea77fe1 Fix reply: dynamically add to DOM instead of page reload 2026-01-30 23:54:42 -05:00
651c8115f6 Fix CSP violation by using event delegation for reply form buttons 2026-01-30 23:51:29 -05:00
6dff92db45 Add debugging for reply button click issue 2026-01-30 23:49:21 -05:00
a8738fdf57 Add comment threading and fix fetch authentication
- Add comment threading/reply functionality with nested display
  - Database migration for parent_comment_id and thread_depth columns
  - Recursive comment rendering with depth-based indentation
  - Reply form with inline UI and smooth animations
  - Thread collapse/expand capability
  - Max thread depth of 3 levels

- Fix 401 authentication errors on API calls
  - Add credentials: 'same-origin' to all fetch calls
  - Affects settings.js, ticket.js, dashboard.js, advanced-search.js
  - Ensures session cookies are sent with requests

- Enhanced comment styling
  - Thread connector lines for visual hierarchy
  - Reply button on comments (up to depth 3)
  - Quote block styling for replies

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 23:43:36 -05:00
1c1eb19876 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>
2026-01-30 19:21:36 -05:00
9b40a714ed Fix critical bugs breaking ticket page and settings modal
- Fix fatal PHP error in UserModel::getAllGroups() - typo 'setCache'
  should be 'setCached', was causing ticket page to fail to render
- Fix settings.js null reference errors when timezone element missing
  on ticket page (only exists on dashboard)
- Fix ESC key detection for settings modal (checked 'block' but modal
  uses 'flex' display)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 19:10:30 -05:00
c3f7593f3c Harden CSP by removing unsafe-inline for scripts
Refactored all inline event handlers (onclick, onchange, onsubmit) to use
addEventListener with data-action attributes and event delegation pattern.

Changes:
- views/*.php: Replaced inline handlers with data-action attributes
- views/admin/*.php: Same refactoring for all admin views
- assets/js/dashboard.js: Added event delegation for bulk/quick action modals
- assets/js/ticket.js: Added event delegation for dynamic elements
- assets/js/markdown.js: Refactored toolbar button handlers
- assets/js/keyboard-shortcuts.js: Refactored modal close button
- SecurityHeadersMiddleware.php: Enabled strict CSP with nonces

The CSP now uses script-src 'self' 'nonce-{nonce}' instead of 'unsafe-inline',
significantly improving XSS protection.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 13:15:55 -05:00
98db586bcf feat: Comment edit/delete, auto-link URLs, markdown tables, mobile fixes
- Add comment edit/delete functionality (owner or admin can modify)
- Add edit/delete buttons to comments in TicketView
- Create update_comment.php and delete_comment.php API endpoints
- Add updateComment() and deleteComment() methods to CommentModel
- Show "(edited)" indicator on modified comments
- Add migration script for updated_at column

- Auto-link URLs in plain text comments (non-markdown)
- Add markdown table support with proper HTML rendering
- Preserve code blocks during markdown parsing

- Fix mobile UI elements showing on desktop (add display:none defaults)
- Add mobile styles for CreateTicketView form elements
- Stack status-priority-row on mobile devices

- Update cache busters to v20260124e
- Update Claude.md and README.md documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 16:59:29 -05:00
d073add6a6 feat: Complete mobile UI overhaul
Major mobile improvements:
- Sticky header with simplified controls
- Slide-out filter sidebar with overlay
- Bottom navigation bar (Home, Filter, New, Settings)
- Stacked toolbar layout
- Full-width modals sliding up from bottom
- Admin dropdown as bottom sheet
- Horizontal scrolling table with touch support
- 44px minimum touch targets throughout
- iOS zoom prevention on inputs
- Landscape mode optimizations

CSS changes:
- Rewrote all mobile styles with correct class names
- Added mobile bottom nav styles
- Fixed toolbar-left, toolbar-center, toolbar-right
- Fixed user-header-left, user-header-right

JS changes:
- initMobileSidebar now creates bottom nav
- Removed style.display = 'none' (CSS handles visibility)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 10:48:32 -05:00
7465fb6fc4 feat: Comprehensive mobile UI improvements
Dashboard mobile changes:
- Sidebar becomes slide-out drawer with overlay
- Added mobile filter toggle button
- Table wrapped for horizontal scroll
- Stats grid: 2 columns on tablet, 1 on phone
- Larger touch targets (44px minimum)
- Full-width modals with better spacing
- Admin dropdown slides up from bottom
- Fixed bulk action bar at bottom

Ticket page mobile changes:
- Stack metadata vertically
- Full-width buttons and inputs
- Scrollable tabs
- Better comment form layout
- Improved timeline readability

General:
- Prevent iOS zoom with 16px input font
- Touch-friendly spacing throughout

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 22:10:29 -05:00
ee317d6662 fix: Keyboard shortcuts for ? key and ESC modal closing
- Fix ? shortcut: removed incorrect !e.shiftKey condition
- ESC now closes all modal types (overlay, settings, advanced search)
- Replace toast-based help with proper styled modal
- ESC also blurs focused inputs before canceling edit mode

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 22:04:39 -05:00
11a593a7dd refactor: Code cleanup and documentation updates
Bug fixes:
- Fix ticket ID extraction using URLSearchParams instead of split()
- Add error handling for query result in get_users.php
- Make Discord webhook URLs dynamic (use HTTP_HOST)

Code cleanup:
- Remove debug console.log statements from dashboard.js and ticket.js
- Add getTicketIdFromUrl() helper function to both JS files

Documentation:
- Update Claude.md: fix web server (nginx not Apache), add new notes
- Update README.md: add keyboard shortcuts, update setup instructions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 22:01:20 -05:00
380b0e1adf fix: Sidebar toggle positioning and documentation updates
- Fix collapsible sidebar toggle button positioning (moved outside sidebar)
- Toggle button now stays visible when sidebar is collapsed
- Update cache busting version
- Update Claude.md with new features documentation
- Update README.md with new features documentation
- Remove migrations folder (no longer needed)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 10:39:55 -05:00
b8a987e4c6 fix: Cache busting and visibility group editing UI
- Add cache busting query params to JS/CSS files (v=20260123)
- Add visibility group selection UI for editing existing tickets
- Add toggleVisibilityGroupsEdit() and getSelectedVisibilityGroups() functions
- Fix visibility data being saved when editing tickets
- Pass $conn to views for UserModel access

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 10:23:19 -05:00
e86a5de3fd feat: Add 9 new features for enhanced UX and security
Quick Wins:
- Feature 1: Ticket linking in comments (#123456789 auto-links)
- Feature 6: Checkbox click area fix (click anywhere in cell)
- Feature 7: User groups display in settings modal

UI Enhancements:
- Feature 4: Collapsible sidebar with localStorage persistence
- Feature 5: Inline ticket preview popup on hover (300ms delay)
- Feature 2: Mobile responsive improvements (44px touch targets, iOS zoom fix)

Major Features:
- Feature 3: Kanban card view with status columns (toggle with localStorage)
- Feature 9: API key generation admin panel (/admin/api-keys)
- Feature 8: Ticket visibility levels (public/internal/confidential)

New files:
- views/admin/ApiKeysView.php
- api/generate_api_key.php
- api/revoke_api_key.php
- migrations/008_ticket_visibility.sql

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 10:01:50 -05:00
c32e9c871b feat: Add timezone setting in preferences + clickable logo
- Add timezone dropdown to settings modal with common timezones
- Save/load timezone preference per user
- Apply user's timezone preference after authentication
- Override system default with user preference if set
- Make dashboard logo clickable (returns to default filters)
- Show current timezone in settings

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 21:54:04 -05:00
bc6a5cecf8 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>
2026-01-20 15:16:14 -05:00
be505b7312 Implement comprehensive improvement plan (Phases 1-6)
Security (Phase 1-2):
- Add SecurityHeadersMiddleware with CSP, X-Frame-Options, etc.
- Add RateLimitMiddleware for API rate limiting
- Add security event logging to AuditLogModel
- Add ResponseHelper for standardized API responses
- Update config.php with security constants

Database (Phase 3):
- Add migration 014 for additional indexes
- Add migration 015 for ticket dependencies
- Add migration 016 for ticket attachments
- Add migration 017 for recurring tickets
- Add migration 018 for custom fields

Features (Phase 4-5):
- Add ticket dependencies with DependencyModel and API
- Add duplicate detection with check_duplicates API
- Add file attachments with AttachmentModel and upload/download APIs
- Add @mentions with autocomplete and highlighting
- Add quick actions on dashboard rows

Collaboration (Phase 5):
- Add mention extraction in CommentModel
- Add mention autocomplete dropdown in ticket.js
- Add mention highlighting CSS styles

Admin & Export (Phase 6):
- Add StatsModel for dashboard widgets
- Add dashboard stats cards (open, critical, unassigned, etc.)
- Add CSV/JSON export via export_tickets API
- Add rich text editor toolbar in markdown.js
- Add RecurringTicketModel with cron job
- Add CustomFieldModel for per-category fields
- Add admin views: RecurringTickets, CustomFields, Workflow,
  Templates, AuditLog, UserActivity
- Add admin APIs: manage_workflows, manage_templates,
  manage_recurring, custom_fields, get_users
- Add admin routes in index.php

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 09:55:01 -05:00
496e8d6c21 fix: Use parseMarkdown instead of marked.parse for comment preview
Fixed markdown preview for comments by replacing marked.parse() calls
with parseMarkdown() function. The application uses a custom markdown
parser (markdown.js), not the marked.js library.

Changes:
- togglePreview(): Use parseMarkdown() instead of marked.parse()
- updatePreview(): Use parseMarkdown() instead of marked.parse()

Resolves issue where markdown preview didn't work for comments but
worked after posting.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-13 15:16:25 -05:00
1b66663307 fix: Pass selectedOption parameter to performStatusChange function
Fixed scope issue where selectedOption variable was not accessible in
performStatusChange(). Updated function signature to accept selectedOption
as a parameter and updated both call sites to pass it.

Resolves error: "selectedOption is not defined" when changing ticket status.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-09 17:08:11 -05:00
63dc2d6314 fix: Correct function closure in ticket.js breaking tab navigation
Fixed syntax error from previous commit where updateTicketStatus()
function had incorrect closing. Changed `});` to `}` at line 434.

This was preventing showTab() and other functions from loading,
breaking the Description/Comments/Activity tab navigation.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-09 17:04:21 -05:00
d86a60c609 feat: Enhance toast system with queuing and manual dismiss
Improved toast notification system with queue management:

**Features Added**:
1. **Toast Queuing**:
   - Multiple toasts no longer replace each other
   - Toasts are queued and displayed sequentially
   - Smooth transitions between queued messages
   - Prevents message loss during rapid operations

2. **Manual Dismissal**:
   - Click [×] button to dismiss toast immediately
   - Useful for long-duration error messages
   - Clears auto-dismiss timeout on manual close
   - Next queued toast appears immediately after dismiss

3. **Queue Management**:
   - Internal toastQueue[] array tracks pending messages
   - currentToast reference prevents overlapping displays
   - dismissToast() handles both auto and manual dismissal
   - Automatic dequeue when toast closes

**Implementation**:
- displayToast() separated from showToast() for queue handling
- timeoutId stored on toast element for cleanup
- Close button styled with terminal aesthetic ([×])
- 300ms fade-out animation preserved

**Benefits**:
✓ No lost messages during bulk operations
✓ Better UX - users can dismiss errors immediately
✓ Clean queue management prevents memory leaks
✓ Maintains terminal aesthetic with minimal close button

Example: Bulk assign 10 tickets with 2 failures now shows:
1. "Bulk assign: 8 succeeded, 2 failed" (toast 1)
2. Next operation's message queued (toast 2)
3. User can dismiss or wait for auto-dismiss

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-09 17:00:35 -05:00
998b85e907 feat: Replace browser alerts with terminal-aesthetic notifications
Replaced all native browser dialogs with custom terminal-style UI:

**Utility Functions** (dashboard.js):
- showConfirmModal() - Reusable confirmation modal with type-based colors
- showInputModal() - Text input modal for user prompts
- Both support keyboard shortcuts (ESC to cancel, Enter to submit)

**Alert Replacements** (22 instances):
- Validation warnings → toast.warning() (amber, 2s)
- Error messages → toast.error() (red, 5s)
- Success messages → toast.success() or toast.warning() with details
- Example: "Bulk close: 5 succeeded, 2 failed" vs simple "Operation complete"

**Confirm Replacements** (3 instances):
- dashboard.js:509 - Bulk close confirmation → showConfirmModal()
- ticket.js:417 - Status change warning → showConfirmModal()
- advanced-search.js:321 - Delete filter → showConfirmModal('error' type)

**Prompt Replacement** (1 instance):
- advanced-search.js:151 - Save filter name → showInputModal()

**Benefits**:
✓ Visual consistency - matches terminal CRT aesthetic
✓ Non-blocking - toasts don't interrupt workflow
✓ Better UX - different colors for different message types
✓ Keyboard friendly - ESC/Enter support in modals
✓ Reusable - modal functions available for future use

All dialogs maintain retro aesthetic with:
- ASCII borders (╚ ╝)
- Terminal green glow
- Monospace fonts
- Color-coded by type (amber warning, red error, cyan info)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-09 16:54:02 -05:00
08a73eb84c fix: Improve Assigned To column sorting behavior
Fixed sorting logic for the "Assigned To" column on dashboard:

Problem:
- "Unassigned" was sorted alphabetically with user names
- Appeared randomly in middle of list (after 'S', before 'V')
- Made it hard to find unassigned tickets when sorted

Solution:
- "Unassigned" tickets now always appear at end of list
- Regardless of sort direction (A→Z or Z→A)
- Assigned user names still sort normally among themselves
- Example A→Z: Alice, Bob, Charlie... Unassigned
- Example Z→A: Zack, Yolanda, Xavier... Unassigned

This keeps unassigned tickets grouped together and predictable.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-09 16:38:16 -05:00
58f2e9d143 feat: Add CSRF tokens to all JavaScript fetch calls and fix XSS
Security improvements across all JavaScript files:

CSRF Protection:
- assets/js/ticket.js - Added X-CSRF-Token header to 5 fetch calls
  (update_ticket.php x3, add_comment.php, assign_ticket.php)
- assets/js/dashboard.js - Added X-CSRF-Token to 8 fetch calls
  (update_ticket.php x2, bulk_operation.php x6)
- assets/js/settings.js - Added X-CSRF-Token to user preferences save
- assets/js/advanced-search.js - Added X-CSRF-Token to filter save/delete

XSS Prevention:
- assets/js/ticket.js:183-209 - Replaced insertAdjacentHTML() with safe
  DOM API (createElement/textContent) to prevent script injection in
  comment rendering. User-supplied data (user_name, created_at) now
  auto-escaped via textContent.

All state-changing operations now include CSRF token validation.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-09 16:13:13 -05:00
962724d811 better filtering and searching 2026-01-09 11:20:27 -05:00
2633d0f962 remove bulk delete 2026-01-08 23:35:49 -05:00
2e7956ce40 Bulk actions update 2026-01-08 23:30:25 -05:00
61e3bd69ff Centered settings modal 2026-01-08 23:19:44 -05:00
83a1ba393a Fix settings 2026-01-08 23:16:29 -05:00
b781a44ed5 Added settings menu 2026-01-08 23:05:03 -05:00
eda9c61724 ui improvements, keyboard shortcuts, and toast not 2026-01-08 22:49:48 -05:00
1a74536079 test fix for the ticket title 2026-01-08 22:40:26 -05:00
649854c86e ticket title not wrapping 2026-01-08 22:36:07 -05:00
d6dae6825c read response.txt once 2026-01-08 12:50:11 -05:00
d76ff7aad0 Fixed api send on ticket resolution 2026-01-08 12:48:06 -05:00