""" Admin configuration for incident intelligence """ from django.contrib import admin from django.utils.html import format_html from django.urls import reverse from django.utils.safestring import mark_safe from .models import ( Incident, IncidentClassification, SeveritySuggestion, IncidentCorrelation, DuplicationDetection, IncidentPattern, AIProcessingLog ) @admin.register(Incident) class IncidentAdmin(admin.ModelAdmin): """Admin interface for Incident model""" list_display = [ 'title', 'severity', 'status', 'category', 'assigned_to', 'reporter', 'created_at', 'ai_processed', 'is_duplicate', 'ai_analysis_link' ] list_filter = [ 'severity', 'status', 'category', 'ai_processed', 'is_duplicate', 'created_at', 'assigned_to', 'reporter' ] search_fields = ['title', 'description', 'free_text'] readonly_fields = [ 'id', 'created_at', 'updated_at', 'ai_processed', 'ai_processing_error', 'last_ai_analysis', 'classification_confidence', 'severity_confidence', 'duplicate_confidence' ] fieldsets = ( ('Basic Information', { 'fields': ('id', 'title', 'description', 'free_text') }), ('Classification', { 'fields': ('category', 'subcategory', 'classification_confidence') }), ('Severity & Priority', { 'fields': ('severity', 'suggested_severity', 'severity_confidence', 'priority') }), ('Status & Assignment', { 'fields': ('status', 'assigned_to', 'reporter') }), ('Impact & Business Context', { 'fields': ('affected_users', 'business_impact', 'estimated_downtime') }), ('AI Processing', { 'fields': ('ai_processed', 'ai_processing_error', 'last_ai_analysis'), 'classes': ('collapse',) }), ('Duplication Detection', { 'fields': ('is_duplicate', 'original_incident', 'duplicate_confidence'), 'classes': ('collapse',) }), ('Timestamps', { 'fields': ('created_at', 'updated_at', 'resolved_at'), 'classes': ('collapse',) }) ) def ai_analysis_link(self, obj): """Link to AI analysis details""" if obj.ai_processed: url = reverse('admin:incident_intelligence_incident_analysis', args=[obj.pk]) return format_html('View Analysis', url) return "Not Processed" ai_analysis_link.short_description = "AI Analysis" actions = ['trigger_ai_analysis', 'mark_as_duplicate', 'mark_as_resolved'] def trigger_ai_analysis(self, request, queryset): """Trigger AI analysis for selected incidents""" from .tasks import batch_process_incidents_ai incident_ids = [str(incident.id) for incident in queryset] batch_process_incidents_ai.delay(incident_ids) self.message_user(request, f"AI analysis triggered for {len(incident_ids)} incidents") trigger_ai_analysis.short_description = "Trigger AI Analysis" def mark_as_duplicate(self, request, queryset): """Mark selected incidents as duplicates""" count = queryset.update(is_duplicate=True) self.message_user(request, f"Marked {count} incidents as duplicates") mark_as_duplicate.short_description = "Mark as Duplicates" def mark_as_resolved(self, request, queryset): """Mark selected incidents as resolved""" count = queryset.update(status='RESOLVED') self.message_user(request, f"Marked {count} incidents as resolved") mark_as_resolved.short_description = "Mark as Resolved" @admin.register(IncidentClassification) class IncidentClassificationAdmin(admin.ModelAdmin): """Admin interface for IncidentClassification model""" list_display = [ 'incident', 'predicted_category', 'predicted_subcategory', 'confidence_score', 'model_version', 'created_at' ] list_filter = ['predicted_category', 'predicted_subcategory', 'model_version', 'created_at'] search_fields = ['incident__title', 'predicted_category', 'predicted_subcategory'] readonly_fields = ['created_at'] fieldsets = ( ('Classification Results', { 'fields': ('incident', 'predicted_category', 'predicted_subcategory', 'confidence_score') }), ('Alternative Classifications', { 'fields': ('alternative_categories',), 'classes': ('collapse',) }), ('NLP Analysis', { 'fields': ('extracted_keywords', 'sentiment_score', 'urgency_indicators'), 'classes': ('collapse',) }), ('Processing Metadata', { 'fields': ('model_version', 'processing_time', 'created_at'), 'classes': ('collapse',) }) ) @admin.register(SeveritySuggestion) class SeveritySuggestionAdmin(admin.ModelAdmin): """Admin interface for SeveritySuggestion model""" list_display = [ 'incident', 'suggested_severity', 'confidence_score', 'user_impact_score', 'business_impact_score', 'technical_impact_score', 'created_at' ] list_filter = ['suggested_severity', 'model_version', 'created_at'] search_fields = ['incident__title', 'reasoning'] readonly_fields = ['created_at'] fieldsets = ( ('Severity Prediction', { 'fields': ('incident', 'suggested_severity', 'confidence_score') }), ('Impact Analysis', { 'fields': ('user_impact_score', 'business_impact_score', 'technical_impact_score') }), ('Reasoning', { 'fields': ('reasoning', 'impact_factors'), 'classes': ('collapse',) }), ('Processing Metadata', { 'fields': ('model_version', 'processing_time', 'created_at'), 'classes': ('collapse',) }) ) @admin.register(IncidentCorrelation) class IncidentCorrelationAdmin(admin.ModelAdmin): """Admin interface for IncidentCorrelation model""" list_display = [ 'primary_incident', 'related_incident', 'correlation_type', 'correlation_strength', 'confidence_score', 'is_problem_indicator', 'created_at' ] list_filter = [ 'correlation_type', 'correlation_strength', 'is_problem_indicator', 'model_version', 'created_at' ] search_fields = ['primary_incident__title', 'related_incident__title'] readonly_fields = ['created_at'] fieldsets = ( ('Correlation Details', { 'fields': ('primary_incident', 'related_incident', 'correlation_type', 'correlation_strength') }), ('Analysis Results', { 'fields': ('confidence_score', 'similarity_score', 'time_difference') }), ('Shared Elements', { 'fields': ('shared_keywords',), 'classes': ('collapse',) }), ('Problem Detection', { 'fields': ('is_problem_indicator', 'problem_description'), 'classes': ('collapse',) }), ('Metadata', { 'fields': ('model_version', 'created_at'), 'classes': ('collapse',) }) ) @admin.register(DuplicationDetection) class DuplicationDetectionAdmin(admin.ModelAdmin): """Admin interface for DuplicationDetection model""" list_display = [ 'incident_a', 'incident_b', 'duplication_type', 'confidence_score', 'recommended_action', 'status', 'created_at' ] list_filter = [ 'duplication_type', 'recommended_action', 'status', 'model_version', 'created_at' ] search_fields = ['incident_a__title', 'incident_b__title'] readonly_fields = ['created_at', 'reviewed_at'] fieldsets = ( ('Incident Pair', { 'fields': ('incident_a', 'incident_b') }), ('Duplication Analysis', { 'fields': ('duplication_type', 'confidence_score', 'similarity_score') }), ('Similarity Breakdown', { 'fields': ('text_similarity', 'temporal_proximity', 'service_similarity'), 'classes': ('collapse',) }), ('Recommendation', { 'fields': ('recommended_action', 'merge_confidence', 'reasoning') }), ('Shared Elements', { 'fields': ('shared_elements',), 'classes': ('collapse',) }), ('Status & Review', { 'fields': ('status', 'reviewed_at', 'reviewed_by'), 'classes': ('collapse',) }), ('Metadata', { 'fields': ('model_version', 'created_at'), 'classes': ('collapse',) }) ) actions = ['approve_merge', 'reject_merge'] def approve_merge(self, request, queryset): """Approve merging of selected duplications""" from .tasks import merge_duplicate_incidents for duplication in queryset.filter(status='DETECTED'): duplication.status = 'REVIEWED' duplication.reviewed_by = request.user duplication.save() merge_duplicate_incidents.delay(duplication.id) self.message_user(request, f"Approved {queryset.count()} duplications for merging") approve_merge.short_description = "Approve Merge" def reject_merge(self, request, queryset): """Reject merging of selected duplications""" count = queryset.filter(status='DETECTED').update( status='REJECTED', reviewed_by=request.user ) self.message_user(request, f"Rejected {count} duplications") reject_merge.short_description = "Reject Merge" @admin.register(IncidentPattern) class IncidentPatternAdmin(admin.ModelAdmin): """Admin interface for IncidentPattern model""" list_display = [ 'name', 'pattern_type', 'incident_count', 'confidence_score', 'is_active', 'is_resolved', 'created_at' ] list_filter = ['pattern_type', 'is_active', 'is_resolved', 'model_version', 'created_at'] search_fields = ['name', 'description'] readonly_fields = ['incident_count', 'created_at', 'updated_at'] filter_horizontal = ['incidents'] fieldsets = ( ('Pattern Information', { 'fields': ('name', 'pattern_type', 'description') }), ('Pattern Characteristics', { 'fields': ('frequency', 'affected_services', 'common_keywords') }), ('Related Incidents', { 'fields': ('incidents', 'incident_count') }), ('Analysis Results', { 'fields': ('confidence_score', 'last_occurrence', 'next_predicted_occurrence') }), ('Status', { 'fields': ('is_active', 'is_resolved') }), ('Metadata', { 'fields': ('model_version', 'created_at', 'updated_at'), 'classes': ('collapse',) }) ) actions = ['resolve_pattern', 'activate_pattern'] def resolve_pattern(self, request, queryset): """Mark selected patterns as resolved""" count = queryset.update(is_resolved=True, is_active=False) self.message_user(request, f"Resolved {count} patterns") resolve_pattern.short_description = "Resolve Patterns" def activate_pattern(self, request, queryset): """Activate selected patterns""" count = queryset.update(is_active=True, is_resolved=False) self.message_user(request, f"Activated {count} patterns") activate_pattern.short_description = "Activate Patterns" @admin.register(AIProcessingLog) class AIProcessingLogAdmin(admin.ModelAdmin): """Admin interface for AIProcessingLog model""" list_display = [ 'processing_type', 'incident', 'status', 'processing_time', 'confidence_score', 'started_at', 'completed_at' ] list_filter = [ 'processing_type', 'status', 'model_version', 'started_at' ] search_fields = ['incident__title', 'error_message'] readonly_fields = ['started_at', 'completed_at'] fieldsets = ( ('Processing Details', { 'fields': ('processing_type', 'status', 'incident', 'related_incidents') }), ('Input/Output Data', { 'fields': ('input_data', 'output_data'), 'classes': ('collapse',) }), ('Error Information', { 'fields': ('error_message',), 'classes': ('collapse',) }), ('Performance Metrics', { 'fields': ('processing_time', 'confidence_score', 'model_version') }), ('Timestamps', { 'fields': ('started_at', 'completed_at'), 'classes': ('collapse',) }) ) def has_add_permission(self, request): """Disable adding new processing logs""" return False def has_change_permission(self, request, obj=None): """Disable editing processing logs""" return False # Custom admin site configuration admin.site.site_header = "ETB Incident Intelligence Admin" admin.site.site_title = "Incident Intelligence" admin.site.index_title = "Incident Intelligence Administration"