Updates
This commit is contained in:
355
ETB-API/incident_intelligence/admin.py
Normal file
355
ETB-API/incident_intelligence/admin.py
Normal file
@@ -0,0 +1,355 @@
|
||||
"""
|
||||
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('<a href="{}">View Analysis</a>', 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"
|
||||
Reference in New Issue
Block a user