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 ( Postmortem, KnowledgeBaseArticle, IncidentRecommendation, LearningPattern, KnowledgeBaseUsage, AutomatedPostmortemGeneration ) @admin.register(Postmortem) class PostmortemAdmin(admin.ModelAdmin): list_display = [ 'title', 'incident_link', 'status', 'severity', 'owner', 'completion_percentage', 'is_overdue', 'created_at' ] list_filter = ['status', 'severity', 'is_automated', 'created_at'] search_fields = ['title', 'incident__title', 'owner__username'] readonly_fields = ['id', 'created_at', 'updated_at', 'completion_percentage', 'is_overdue'] fieldsets = ( ('Basic Information', { 'fields': ('id', 'title', 'incident', 'status', 'severity') }), ('Content', { 'fields': ('executive_summary', 'timeline', 'root_cause_analysis', 'impact_assessment', 'lessons_learned', 'action_items') }), ('Automation', { 'fields': ('is_automated', 'generation_confidence', 'auto_generated_sections') }), ('Workflow', { 'fields': ('owner', 'reviewers', 'approver', 'due_date') }), ('Context', { 'fields': ('related_incidents', 'affected_services', 'affected_teams') }), ('Timestamps', { 'fields': ('created_at', 'updated_at', 'published_at'), 'classes': ('collapse',) }) ) filter_horizontal = ['reviewers', 'related_incidents'] def incident_link(self, obj): if obj.incident: url = reverse('admin:incident_intelligence_incident_change', args=[obj.incident.id]) return format_html('{}', url, obj.incident.title) return '-' incident_link.short_description = 'Incident' def completion_percentage(self, obj): percentage = obj.get_completion_percentage() color = 'green' if percentage >= 80 else 'orange' if percentage >= 50 else 'red' return format_html( '{:.1f}%', color, percentage ) completion_percentage.short_description = 'Completion' def is_overdue(self, obj): if obj.is_overdue: return format_html('Yes') return format_html('No') is_overdue.short_description = 'Overdue' @admin.register(KnowledgeBaseArticle) class KnowledgeBaseArticleAdmin(admin.ModelAdmin): list_display = [ 'title', 'article_type', 'category', 'status', 'view_count', 'author', 'is_due_for_review', 'created_at' ] list_filter = ['article_type', 'category', 'status', 'difficulty_level', 'is_featured', 'created_at'] search_fields = ['title', 'content', 'summary', 'tags', 'author__username'] readonly_fields = ['id', 'created_at', 'updated_at', 'view_count', 'is_due_for_review'] fieldsets = ( ('Basic Information', { 'fields': ('id', 'title', 'slug', 'article_type', 'category', 'subcategory') }), ('Content', { 'fields': ('content', 'summary', 'tags', 'search_keywords') }), ('Classification', { 'fields': ('related_services', 'related_components', 'difficulty_level') }), ('Status & Workflow', { 'fields': ('status', 'is_featured', 'author', 'last_updated_by', 'maintainer') }), ('Review Schedule', { 'fields': ('last_reviewed', 'next_review_due', 'is_due_for_review') }), ('External Links', { 'fields': ('confluence_url', 'wiki_url', 'external_references'), 'classes': ('collapse',) }), ('Relationships', { 'fields': ('related_incidents', 'source_postmortems'), 'classes': ('collapse',) }), ('Statistics', { 'fields': ('view_count', 'created_at', 'updated_at'), 'classes': ('collapse',) }) ) filter_horizontal = ['related_incidents', 'source_postmortems'] def is_due_for_review(self, obj): if obj.is_due_for_review(): return format_html('Yes') return format_html('No') is_due_for_review.short_description = 'Due for Review' @admin.register(IncidentRecommendation) class IncidentRecommendationAdmin(admin.ModelAdmin): list_display = [ 'title', 'incident_link', 'recommendation_type', 'confidence_level', 'similarity_score', 'is_applied', 'created_at' ] list_filter = ['recommendation_type', 'confidence_level', 'is_applied', 'created_at'] search_fields = ['title', 'description', 'incident__title', 'reasoning'] readonly_fields = ['id', 'created_at', 'updated_at'] fieldsets = ( ('Basic Information', { 'fields': ('id', 'incident', 'recommendation_type', 'title', 'description') }), ('Scores', { 'fields': ('similarity_score', 'confidence_level', 'confidence_score') }), ('Related Objects', { 'fields': ('related_incident', 'knowledge_article', 'suggested_expert') }), ('Recommendation Details', { 'fields': ('suggested_actions', 'expected_outcome', 'time_to_implement') }), ('Usage Tracking', { 'fields': ('is_applied', 'applied_at', 'applied_by', 'effectiveness_rating') }), ('AI Analysis', { 'fields': ('reasoning', 'matching_factors', 'model_version'), 'classes': ('collapse',) }), ('Timestamps', { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }) ) def incident_link(self, obj): if obj.incident: url = reverse('admin:incident_intelligence_incident_change', args=[obj.incident.id]) return format_html('{}', url, obj.incident.title) return '-' incident_link.short_description = 'Incident' @admin.register(LearningPattern) class LearningPatternAdmin(admin.ModelAdmin): list_display = [ 'name', 'pattern_type', 'frequency', 'success_rate', 'confidence_score', 'is_validated', 'times_applied' ] list_filter = ['pattern_type', 'is_validated', 'created_at'] search_fields = ['name', 'description', 'validated_by__username'] readonly_fields = ['id', 'created_at', 'updated_at'] fieldsets = ( ('Basic Information', { 'fields': ('id', 'name', 'pattern_type', 'description') }), ('Pattern Characteristics', { 'fields': ('frequency', 'success_rate', 'confidence_score') }), ('Pattern Details', { 'fields': ('triggers', 'actions', 'outcomes') }), ('Source Data', { 'fields': ('source_incidents', 'source_postmortems'), 'classes': ('collapse',) }), ('Validation', { 'fields': ('is_validated', 'validated_by', 'validation_notes') }), ('Usage Tracking', { 'fields': ('times_applied', 'last_applied') }), ('Timestamps', { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }) ) filter_horizontal = ['source_incidents', 'source_postmortems'] @admin.register(KnowledgeBaseUsage) class KnowledgeBaseUsageAdmin(admin.ModelAdmin): list_display = [ 'user', 'usage_type', 'article_link', 'recommendation_link', 'incident_link', 'created_at' ] list_filter = ['usage_type', 'created_at'] search_fields = ['user__username', 'knowledge_article__title', 'recommendation__title'] readonly_fields = ['id', 'created_at'] def article_link(self, obj): if obj.knowledge_article: url = reverse('admin:knowledge_learning_knowledgebasearticle_change', args=[obj.knowledge_article.id]) return format_html('{}', url, obj.knowledge_article.title) return '-' article_link.short_description = 'Article' def recommendation_link(self, obj): if obj.recommendation: url = reverse('admin:knowledge_learning_incidentrecommendation_change', args=[obj.recommendation.id]) return format_html('{}', url, obj.recommendation.title) return '-' recommendation_link.short_description = 'Recommendation' def incident_link(self, obj): if obj.incident: url = reverse('admin:incident_intelligence_incident_change', args=[obj.incident.id]) return format_html('{}', url, obj.incident.title) return '-' incident_link.short_description = 'Incident' @admin.register(AutomatedPostmortemGeneration) class AutomatedPostmortemGenerationAdmin(admin.ModelAdmin): list_display = [ 'incident_link', 'status', 'generation_trigger', 'processing_time', 'model_version', 'started_at' ] list_filter = ['status', 'generation_trigger', 'model_version', 'started_at'] search_fields = ['incident__title', 'error_message'] readonly_fields = ['id', 'started_at', 'completed_at'] fieldsets = ( ('Basic Information', { 'fields': ('id', 'incident', 'status', 'generation_trigger') }), ('Input Data', { 'fields': ('incident_data', 'timeline_data', 'log_data'), 'classes': ('collapse',) }), ('Generation Results', { 'fields': ('generated_content', 'confidence_scores', 'quality_metrics', 'generated_postmortem'), 'classes': ('collapse',) }), ('Processing Details', { 'fields': ('processing_time', 'model_version', 'error_message') }), ('Timestamps', { 'fields': ('started_at', 'completed_at') }) ) def incident_link(self, obj): if obj.incident: url = reverse('admin:incident_intelligence_incident_change', args=[obj.incident.id]) return format_html('{}', url, obj.incident.title) return '-' incident_link.short_description = 'Incident'