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>
This commit is contained in:
@@ -1172,10 +1172,330 @@ body.dark-mode .editable {
|
||||
.ticket-tabs {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
.tab-btn {
|
||||
width: 100%;
|
||||
border: 2px solid var(--terminal-green);
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== ATTACHMENT STYLES ===== */
|
||||
|
||||
/* Upload Zone */
|
||||
.upload-zone {
|
||||
border: 3px dashed var(--terminal-green);
|
||||
border-radius: 0;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
background: var(--bg-primary);
|
||||
}
|
||||
|
||||
.upload-zone:hover {
|
||||
border-color: var(--terminal-amber);
|
||||
background: rgba(0, 255, 65, 0.05);
|
||||
}
|
||||
|
||||
.upload-zone.drag-over {
|
||||
border-color: var(--terminal-amber);
|
||||
background: rgba(241, 196, 15, 0.1);
|
||||
box-shadow: 0 0 20px rgba(241, 196, 15, 0.3);
|
||||
}
|
||||
|
||||
.upload-zone-content {
|
||||
color: var(--terminal-green);
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.upload-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.upload-hint {
|
||||
font-size: 0.85rem;
|
||||
color: var(--terminal-green-dim);
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
/* Progress Bar */
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
border: 2px solid var(--terminal-green);
|
||||
background: var(--bg-primary);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: var(--terminal-green);
|
||||
transition: width 0.3s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.progress-fill::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
rgba(255, 255, 255, 0.2) 50%,
|
||||
transparent 100%
|
||||
);
|
||||
animation: progress-shimmer 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes progress-shimmer {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(100%); }
|
||||
}
|
||||
|
||||
/* Attachments Grid */
|
||||
.attachments-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.attachment-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 0.75rem 1rem;
|
||||
border: 1px solid var(--terminal-green);
|
||||
background: var(--bg-primary);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.attachment-item:hover {
|
||||
border-color: var(--terminal-amber);
|
||||
background: rgba(0, 255, 65, 0.05);
|
||||
}
|
||||
|
||||
.attachment-icon {
|
||||
font-size: 1.5rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.attachment-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.attachment-name {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.95rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.attachment-name a {
|
||||
color: var(--terminal-green);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.attachment-name a:hover {
|
||||
color: var(--terminal-amber);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.attachment-meta {
|
||||
font-size: 0.8rem;
|
||||
color: var(--terminal-green-dim);
|
||||
font-family: var(--font-mono);
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.attachment-actions {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.btn-small {
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
color: var(--priority-1);
|
||||
border-color: var(--priority-1);
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background: var(--priority-1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Mobile responsiveness for attachments */
|
||||
@media (max-width: 768px) {
|
||||
.attachment-item {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.attachment-info {
|
||||
flex-basis: calc(100% - 4rem);
|
||||
}
|
||||
|
||||
.attachment-actions {
|
||||
flex-basis: 100%;
|
||||
justify-content: flex-end;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== @MENTION HIGHLIGHTING STYLES ===== */
|
||||
|
||||
/* Mention styling in comments */
|
||||
.mention {
|
||||
color: var(--terminal-cyan);
|
||||
background: rgba(0, 255, 255, 0.1);
|
||||
padding: 0.1rem 0.3rem;
|
||||
border-radius: 0;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.mention:hover {
|
||||
background: rgba(0, 255, 255, 0.2);
|
||||
text-shadow: 0 0 5px var(--terminal-cyan);
|
||||
}
|
||||
|
||||
.mention::before {
|
||||
content: '@';
|
||||
}
|
||||
|
||||
/* Mention Autocomplete Dropdown */
|
||||
.mention-autocomplete {
|
||||
position: absolute;
|
||||
background: var(--bg-primary);
|
||||
border: 2px solid var(--terminal-green);
|
||||
border-radius: 0;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
min-width: 200px;
|
||||
box-shadow: 0 0 10px rgba(0, 255, 65, 0.3);
|
||||
}
|
||||
|
||||
.mention-autocomplete.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mention-option {
|
||||
padding: 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
font-family: var(--font-mono);
|
||||
color: var(--terminal-green);
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.mention-option:hover,
|
||||
.mention-option.selected {
|
||||
background: rgba(0, 255, 65, 0.1);
|
||||
color: var(--terminal-amber);
|
||||
}
|
||||
|
||||
.mention-option .mention-username {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.mention-option .mention-displayname {
|
||||
color: var(--terminal-green-dim);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
/* ===== RICH TEXT EDITOR TOOLBAR ===== */
|
||||
|
||||
.editor-toolbar {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
padding: 0.5rem;
|
||||
border: 2px solid var(--terminal-green);
|
||||
border-bottom: none;
|
||||
background: var(--bg-secondary);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.editor-toolbar button {
|
||||
padding: 0.4rem 0.6rem;
|
||||
background: var(--bg-primary);
|
||||
border: 1px solid var(--terminal-green);
|
||||
color: var(--terminal-green);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.85rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
min-width: 32px;
|
||||
}
|
||||
|
||||
.editor-toolbar button:hover {
|
||||
background: rgba(0, 255, 65, 0.1);
|
||||
color: var(--terminal-amber);
|
||||
border-color: var(--terminal-amber);
|
||||
}
|
||||
|
||||
.editor-toolbar button:active {
|
||||
background: rgba(0, 255, 65, 0.2);
|
||||
}
|
||||
|
||||
.editor-toolbar .toolbar-separator {
|
||||
width: 1px;
|
||||
background: var(--terminal-green-dim);
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
|
||||
/* Connect toolbar to textarea */
|
||||
.editor-with-toolbar textarea {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
/* ===== EXPORT BUTTON ===== */
|
||||
|
||||
.export-dropdown {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.export-dropdown-content {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
background: var(--bg-primary);
|
||||
border: 2px solid var(--terminal-green);
|
||||
min-width: 150px;
|
||||
z-index: 100;
|
||||
box-shadow: 0 0 10px rgba(0, 255, 65, 0.3);
|
||||
}
|
||||
|
||||
.export-dropdown:hover .export-dropdown-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.export-dropdown-content a {
|
||||
display: block;
|
||||
padding: 0.5rem 1rem;
|
||||
color: var(--terminal-green);
|
||||
text-decoration: none;
|
||||
font-family: var(--font-mono);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.export-dropdown-content a:hover {
|
||||
background: rgba(0, 255, 65, 0.1);
|
||||
color: var(--terminal-amber);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user