2025-05-16 20:02:49 -04:00
< ? php
// This file contains the HTML template for creating a new ticket
?>
<! DOCTYPE html >
< html lang = " en " >
< head >
< meta charset = " UTF-8 " >
< meta name = " viewport " content = " width=device-width, initial-scale=1.0 " >
< title > Create New Ticket </ title >
< link rel = " icon " type = " image/png " href = " <?php echo $GLOBALS['config'] ['ASSETS_URL']; ?>/images/favicon.png " >
2026-01-24 16:59:29 -05:00
< link rel = " stylesheet " href = " <?php echo $GLOBALS['config'] ['ASSETS_URL']; ?>/css/dashboard.css?v=20260124e " >
< link rel = " stylesheet " href = " <?php echo $GLOBALS['config'] ['ASSETS_URL']; ?>/css/ticket.css?v=20260124e " >
< script src = " <?php echo $GLOBALS['config'] ['ASSETS_URL']; ?>/js/dashboard.js?v=20260124e " ></ script >
2026-01-09 15:05:20 -05:00
< script >
// CSRF Token for AJAX requests
window . CSRF_TOKEN = ' < ? php
require_once __DIR__ . '/../middleware/CsrfMiddleware.php' ;
echo CsrfMiddleware :: getToken ();
?> ';
</ script >
2025-05-16 20:02:49 -04:00
</ head >
< body >
2026-01-07 10:52:10 -05:00
< div class = " user-header " >
< div class = " user-header-left " >
< a href = " / " class = " back-link " > ← Dashboard </ a >
2025-05-16 20:02:49 -04:00
</ div >
2026-01-07 10:52:10 -05:00
< div class = " user-header-right " >
< ? php if ( isset ( $GLOBALS [ 'currentUser' ])) : ?>
< span class = " user-name " > 👤 < ? php echo htmlspecialchars ( $GLOBALS [ 'currentUser' ][ 'display_name' ] ? ? $GLOBALS [ 'currentUser' ][ 'username' ]); ?> </span>
< ? php if ( $GLOBALS [ 'currentUser' ][ 'is_admin' ]) : ?>
< span class = " admin-badge " > Admin </ span >
< ? php endif ; ?>
< ? php endif ; ?>
</ div >
</ div >
<!-- OUTER FRAME : Create Ticket Form Container -->
< div class = " ascii-frame-outer " >
< span class = " bottom-left-corner " > ╚ </ span >
< span class = " bottom-right-corner " > ╝ </ span >
<!-- SECTION 1 : Form Header -->
< div class = " ascii-section-header " > Create New Ticket </ div >
< div class = " ascii-content " >
< div class = " ascii-frame-inner " >
< div class = " ticket-header " >
< h2 > New Ticket Form </ h2 >
< p style = " color: var(--terminal-green); font-family: var(--font-mono); font-size: 0.9rem; margin-top: 0.5rem; " >
Complete the form below to create a new ticket
</ p >
</ div >
</ div >
</ div >
2025-05-16 20:02:49 -04:00
< ? php if ( isset ( $error )) : ?>
2026-01-07 10:52:10 -05:00
<!-- DIVIDER -->
< div class = " ascii-divider " ></ div >
<!-- ERROR SECTION -->
< div class = " ascii-content " >
< div class = " ascii-frame-inner " >
< div class = " error-message " style = " color: var(--priority-1); border: 2px solid var(--priority-1); padding: 1rem; background: rgba(231, 76, 60, 0.1); " >
< strong > ⚠ Error :</ strong > < ? php echo $error ; ?>
</ div >
</ div >
</ div >
2025-05-16 20:02:49 -04:00
< ? php endif ; ?>
2026-01-07 10:52:10 -05:00
<!-- DIVIDER -->
< div class = " ascii-divider " ></ div >
2025-05-16 20:02:49 -04:00
< form method = " POST " action = " <?php echo $GLOBALS['config'] ['BASE_URL']; ?>/ticket/create " class = " ticket-form " >
2026-01-01 19:00:42 -05:00
2026-01-07 10:52:10 -05:00
<!-- SECTION 2 : Template Selection -->
< div class = " ascii-section-header " > Template Selection </ div >
< div class = " ascii-content " >
< div class = " ascii-frame-inner " >
< div class = " detail-group " >
< label for = " templateSelect " > Use Template ( Optional ) </ label >
< select id = " templateSelect " class = " editable " onchange = " loadTemplate() " >
< option value = " " >-- No Template --</ option >
< ? php if ( isset ( $templates ) && ! empty ( $templates )) : ?>
< ? php foreach ( $templates as $template ) : ?>
< option value = " <?php echo $template['template_id'] ; ?> " >
< ? php echo htmlspecialchars ( $template [ 'template_name' ]); ?>
</ option >
< ? php endforeach ; ?>
< ? php endif ; ?>
2025-05-16 20:02:49 -04:00
</ select >
2026-01-07 10:52:10 -05:00
< p style = " color: var(--terminal-green); font-size: 0.85rem; margin-top: 0.5rem; font-family: var(--font-mono); " >
Select a template to auto - fill form fields
</ p >
2025-05-16 20:02:49 -04:00
</ div >
2026-01-07 10:52:10 -05:00
</ div >
</ div >
<!-- DIVIDER -->
< div class = " ascii-divider " ></ div >
<!-- SECTION 3 : Basic Information -->
< div class = " ascii-section-header " > Basic Information </ div >
< div class = " ascii-content " >
< div class = " ascii-frame-inner " >
< div class = " detail-group " >
< label for = " title " > Ticket Title *</ label >
< input type = " text " id = " title " name = " title " class = " editable " required placeholder = " Enter a descriptive title for this ticket " >
2025-05-16 20:02:49 -04:00
</ div >
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
<!-- Duplicate Warning Area -->
< div id = " duplicateWarning " style = " display: none; margin-top: 1rem; padding: 1rem; border: 2px solid var(--terminal-amber); background: rgba(241, 196, 15, 0.1); " >
< div style = " color: var(--terminal-amber); font-weight: bold; margin-bottom: 0.5rem; " >
Possible Duplicates Found
</ div >
< div id = " duplicatesList " ></ div >
</ div >
2026-01-07 10:52:10 -05:00
</ div >
</ div >
<!-- DIVIDER -->
< div class = " ascii-divider " ></ div >
<!-- SECTION 4 : Ticket Metadata -->
< div class = " ascii-section-header " > Ticket Metadata </ div >
< div class = " ascii-content " >
< div class = " ascii-frame-inner " >
< div class = " detail-group status-priority-row " >
< div class = " detail-quarter " >
< label for = " status " > Status </ label >
< select id = " status " name = " status " class = " editable " >
< option value = " Open " selected > Open </ option >
< option value = " Closed " > Closed </ option >
</ select >
</ div >
< div class = " detail-quarter " >
< label for = " priority " > Priority </ label >
< select id = " priority " name = " priority " class = " editable " >
< option value = " 1 " > P1 - Critical Impact </ option >
< option value = " 2 " > P2 - High Impact </ option >
< option value = " 3 " > P3 - Medium Impact </ option >
< option value = " 4 " selected > P4 - Low Impact </ option >
</ select >
</ div >
< div class = " detail-quarter " >
< label for = " category " > Category </ label >
< select id = " category " name = " category " class = " editable " >
< option value = " Hardware " > Hardware </ option >
< option value = " Software " > Software </ option >
< option value = " Network " > Network </ option >
< option value = " Security " > Security </ option >
< option value = " General " selected > General </ option >
</ select >
</ div >
< div class = " detail-quarter " >
< label for = " type " > Type </ label >
< select id = " type " name = " type " class = " editable " >
< option value = " Maintenance " > Maintenance </ option >
< option value = " Install " > Install </ option >
< option value = " Task " > Task </ option >
< option value = " Upgrade " > Upgrade </ option >
< option value = " Issue " selected > Issue </ option >
</ select >
</ div >
2025-05-16 20:02:49 -04:00
</ div >
</ div >
2026-01-07 10:52:10 -05:00
</ div >
<!-- DIVIDER -->
< div class = " ascii-divider " ></ div >
2026-01-23 10:01:50 -05:00
<!-- SECTION 5 : Visibility Settings -->
< div class = " ascii-section-header " > Visibility Settings </ div >
< div class = " ascii-content " >
< div class = " ascii-frame-inner " >
< div class = " detail-group " >
< label for = " visibility " > Ticket Visibility </ label >
< select id = " visibility " name = " visibility " class = " editable " onchange = " toggleVisibilityGroups() " >
< option value = " public " selected > Public - All authenticated users </ option >
< option value = " internal " > Internal - Specific groups only </ option >
< option value = " confidential " > Confidential - Creator , assignee , admins only </ option >
</ select >
< p style = " color: var(--terminal-green); font-size: 0.85rem; margin-top: 0.5rem; font-family: var(--font-mono); " >
Controls who can view this ticket
</ p >
</ div >
< div id = " visibilityGroupsContainer " class = " detail-group " style = " display: none; margin-top: 1rem; " >
< label > Allowed Groups </ label >
< div class = " visibility-groups-list " style = " display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 0.5rem; " >
< ? php
// Get all available groups
require_once __DIR__ . '/../models/UserModel.php' ;
$userModel = new UserModel ( $conn );
$allGroups = $userModel -> getAllGroups ();
foreach ( $allGroups as $group ) :
?>
< label style = " display: flex; align-items: center; gap: 0.5rem; cursor: pointer; " >
< input type = " checkbox " name = " visibility_groups[] " value = " <?php echo htmlspecialchars( $group ); ?> " class = " visibility-group-checkbox " >
< span class = " group-badge " >< ? php echo htmlspecialchars ( $group ); ?> </span>
</ label >
< ? php endforeach ; ?>
< ? php if ( empty ( $allGroups )) : ?>
< span style = " color: var(--text-muted); " > No groups available </ span >
< ? php endif ; ?>
</ div >
< p style = " color: var(--terminal-amber); font-size: 0.85rem; margin-top: 0.5rem; font-family: var(--font-mono); " >
Select which groups can view this ticket
</ p >
</ div >
</ div >
</ div >
<!-- DIVIDER -->
< div class = " ascii-divider " ></ div >
<!-- SECTION 6 : Detailed Description -->
2026-01-07 10:52:10 -05:00
< div class = " ascii-section-header " > Detailed Description </ div >
< div class = " ascii-content " >
< div class = " ascii-frame-inner " >
< div class = " detail-group full-width " >
< label for = " description " > Description *</ label >
< textarea id = " description " name = " description " class = " editable " rows = " 15 " required placeholder = " Provide a detailed description of the ticket... " ></ textarea >
</ div >
2025-05-16 20:02:49 -04:00
</ div >
</ div >
2026-01-07 10:52:10 -05:00
<!-- DIVIDER -->
< div class = " ascii-divider " ></ div >
<!-- SECTION 6 : Form Actions -->
< div class = " ascii-section-header " > Form Actions </ div >
< div class = " ascii-content " >
< div class = " ascii-frame-inner " >
< div class = " ticket-footer " >
< button type = " submit " class = " btn primary " > Create Ticket </ button >
< button type = " button " onclick = " window.location.href='<?php echo $GLOBALS['config'] ['BASE_URL']; ?>/' " class = " btn back-btn " > Cancel </ button >
</ div >
</ div >
2025-05-16 20:02:49 -04:00
</ div >
2026-01-07 10:52:10 -05:00
2025-05-16 20:02:49 -04:00
</ form >
</ div >
2026-01-07 10:52:10 -05:00
<!-- END OUTER FRAME -->
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
< script >
// Duplicate detection with debounce
let duplicateCheckTimeout = null ;
document . getElementById ( 'title' ) . addEventListener ( 'input' , function () {
clearTimeout ( duplicateCheckTimeout );
const title = this . value . trim ();
if ( title . length < 5 ) {
document . getElementById ( 'duplicateWarning' ) . style . display = 'none' ;
return ;
}
// Debounce: wait 500ms after user stops typing
duplicateCheckTimeout = setTimeout (() => {
checkForDuplicates ( title );
}, 500 );
});
function checkForDuplicates ( title ) {
fetch ( '/api/check_duplicates.php?title=' + encodeURIComponent ( title ))
. then ( response => response . json ())
. then ( data => {
const warningDiv = document . getElementById ( 'duplicateWarning' );
const listDiv = document . getElementById ( 'duplicatesList' );
if ( data . success && data . duplicates && data . duplicates . length > 0 ) {
let html = '<ul style="margin: 0; padding-left: 1.5rem; color: var(--terminal-green);">' ;
data . duplicates . forEach ( dup => {
html += ` < li style = " margin-bottom: 0.5rem; " >
< a href = " /ticket/ ${ escapeHtml(dup.ticket_id) } " target = " _blank " style = " color: var(--terminal-green); " >
#${escapeHtml(dup.ticket_id)}
</ a >
- $ { escapeHtml ( dup . title )}
< span style = " color: var(--terminal-amber); " > ( $ { dup . similarity } % match , $ { escapeHtml ( dup . status )}) </ span >
</ li > ` ;
});
html += '</ul>' ;
html += '<p style="margin-top: 0.5rem; font-size: 0.85rem; color: var(--terminal-green-dim);">Consider checking these tickets before creating a new one.</p>' ;
listDiv . innerHTML = html ;
warningDiv . style . display = 'block' ;
} else {
warningDiv . style . display = 'none' ;
}
})
. catch ( error => {
console . error ( 'Error checking duplicates:' , error );
});
}
function escapeHtml ( text ) {
const div = document . createElement ( 'div' );
div . textContent = text ;
return div . innerHTML ;
}
2026-01-23 10:01:50 -05:00
function toggleVisibilityGroups () {
const visibility = document . getElementById ( 'visibility' ) . value ;
const groupsContainer = document . getElementById ( 'visibilityGroupsContainer' );
if ( visibility === 'internal' ) {
groupsContainer . style . display = 'block' ;
} else {
groupsContainer . style . display = 'none' ;
// Uncheck all group checkboxes when hiding
document . querySelectorAll ( '.visibility-group-checkbox' ) . forEach ( cb => cb . checked = false );
}
}
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
</ script >
2025-05-16 20:02:49 -04:00
</ body >
2026-01-07 10:52:10 -05:00
</ html >