Files
ETB/ETB-API/sla_oncall/admin.py
Iliyan Angelov 6b247e5b9f Updates
2025-09-19 11:58:53 +03:00

293 lines
9.2 KiB
Python

"""
Admin configuration for SLA & On-Call Management
"""
from django.contrib import admin
from django.utils.html import format_html
from django.utils import timezone
from datetime import timedelta
from .models import (
BusinessHours,
SLADefinition,
EscalationPolicy,
OnCallRotation,
OnCallAssignment,
SLAInstance,
EscalationInstance,
NotificationTemplate,
)
@admin.register(BusinessHours)
class BusinessHoursAdmin(admin.ModelAdmin):
list_display = ['name', 'timezone', 'weekday_start', 'weekday_end', 'is_active', 'is_default']
list_filter = ['is_active', 'is_default', 'timezone']
search_fields = ['name', 'description']
ordering = ['name']
fieldsets = (
('Basic Information', {
'fields': ('name', 'description', 'timezone')
}),
('Business Hours', {
'fields': ('weekday_start', 'weekday_end', 'weekend_start', 'weekend_end')
}),
('Overrides', {
'fields': ('day_overrides', 'holiday_calendar'),
'classes': ('collapse',)
}),
('Status', {
'fields': ('is_active', 'is_default')
}),
('Metadata', {
'fields': ('created_by', 'created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
readonly_fields = ['created_at', 'updated_at']
@admin.register(SLADefinition)
class SLADefinitionAdmin(admin.ModelAdmin):
list_display = [
'name', 'sla_type', 'target_duration_minutes',
'business_hours_only', 'is_active', 'is_default'
]
list_filter = ['sla_type', 'business_hours_only', 'is_active', 'is_default']
search_fields = ['name', 'description']
ordering = ['name']
fieldsets = (
('Basic Information', {
'fields': ('name', 'description', 'sla_type')
}),
('Targeting Criteria', {
'fields': ('incident_categories', 'incident_severities', 'incident_priorities')
}),
('SLA Configuration', {
'fields': ('target_duration_minutes', 'business_hours_only', 'business_hours')
}),
('Escalation', {
'fields': ('escalation_enabled', 'escalation_threshold_percent')
}),
('Status', {
'fields': ('is_active', 'is_default')
}),
('Metadata', {
'fields': ('created_by', 'created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
readonly_fields = ['created_at', 'updated_at']
@admin.register(EscalationPolicy)
class EscalationPolicyAdmin(admin.ModelAdmin):
list_display = [
'name', 'escalation_type', 'trigger_condition',
'trigger_delay_minutes', 'is_active'
]
list_filter = ['escalation_type', 'trigger_condition', 'is_active']
search_fields = ['name', 'description']
ordering = ['name']
fieldsets = (
('Basic Information', {
'fields': ('name', 'description', 'escalation_type', 'trigger_condition')
}),
('Targeting', {
'fields': ('incident_severities', 'incident_categories')
}),
('Configuration', {
'fields': ('trigger_delay_minutes', 'escalation_steps')
}),
('Notifications', {
'fields': ('notification_channels', 'notification_templates'),
'classes': ('collapse',)
}),
('Status', {
'fields': ('is_active', 'is_default')
}),
('Metadata', {
'fields': ('created_by', 'created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
readonly_fields = ['created_at', 'updated_at']
@admin.register(OnCallRotation)
class OnCallRotationAdmin(admin.ModelAdmin):
list_display = [
'name', 'rotation_type', 'team_name', 'external_system', 'status'
]
list_filter = ['rotation_type', 'external_system', 'status']
search_fields = ['name', 'team_name', 'description']
ordering = ['name']
fieldsets = (
('Basic Information', {
'fields': ('name', 'description', 'rotation_type', 'status')
}),
('Team Configuration', {
'fields': ('team_name', 'team_description')
}),
('Schedule', {
'fields': ('schedule_config', 'timezone')
}),
('External Integration', {
'fields': ('external_system', 'external_system_id', 'integration_config'),
'classes': ('collapse',)
}),
('Metadata', {
'fields': ('created_by', 'created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
readonly_fields = ['created_at', 'updated_at']
@admin.register(OnCallAssignment)
class OnCallAssignmentAdmin(admin.ModelAdmin):
list_display = [
'user', 'rotation', 'start_time', 'end_time', 'status', 'incidents_handled'
]
list_filter = ['status', 'rotation', 'start_time']
search_fields = ['user__username', 'user__email', 'rotation__name']
ordering = ['-start_time']
fieldsets = (
('Assignment Details', {
'fields': ('rotation', 'user', 'start_time', 'end_time', 'status')
}),
('Handoff Information', {
'fields': ('handoff_notes', 'handed_off_from', 'handoff_time'),
'classes': ('collapse',)
}),
('Performance', {
'fields': ('incidents_handled', 'response_time_avg')
}),
('Metadata', {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
readonly_fields = ['created_at', 'updated_at']
@admin.register(SLAInstance)
class SLAInstanceAdmin(admin.ModelAdmin):
list_display = [
'incident', 'sla_definition', 'status', 'target_time',
'escalation_triggered', 'time_remaining_display'
]
list_filter = ['status', 'escalation_triggered', 'sla_definition__sla_type']
search_fields = ['incident__title', 'sla_definition__name']
ordering = ['-created_at']
fieldsets = (
('SLA Details', {
'fields': ('sla_definition', 'incident', 'status', 'target_time')
}),
('Timing', {
'fields': ('started_at', 'met_at', 'breached_at')
}),
('Escalation', {
'fields': ('escalation_policy', 'escalation_triggered',
'escalation_triggered_at', 'escalation_level')
}),
('Performance', {
'fields': ('response_time', 'resolution_time')
}),
('Metadata', {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
readonly_fields = ['created_at', 'updated_at', 'started_at']
def time_remaining_display(self, obj):
"""Display time remaining with color coding"""
if obj.status == 'ACTIVE':
remaining = obj.time_remaining
if remaining > timedelta(hours=1):
color = 'green'
elif remaining > timedelta(minutes=15):
color = 'orange'
else:
color = 'red'
return format_html(
'<span style="color: {};">{}</span>',
color,
str(remaining).split('.')[0] if remaining else 'Expired'
)
return '-'
time_remaining_display.short_description = 'Time Remaining'
@admin.register(EscalationInstance)
class EscalationInstanceAdmin(admin.ModelAdmin):
list_display = [
'incident', 'escalation_policy', 'status', 'escalation_level',
'triggered_at', 'current_step'
]
list_filter = ['status', 'escalation_level', 'escalation_policy__escalation_type']
search_fields = ['incident__title', 'escalation_policy__name']
ordering = ['-created_at']
fieldsets = (
('Escalation Details', {
'fields': ('escalation_policy', 'incident', 'sla_instance', 'status')
}),
('Progress', {
'fields': ('escalation_level', 'current_step')
}),
('Timing', {
'fields': ('triggered_at', 'acknowledged_at', 'resolved_at')
}),
('Actions', {
'fields': ('notifications_sent', 'actions_taken'),
'classes': ('collapse',)
}),
('Metadata', {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
readonly_fields = ['created_at', 'updated_at']
@admin.register(NotificationTemplate)
class NotificationTemplateAdmin(admin.ModelAdmin):
list_display = [
'name', 'template_type', 'channel_type', 'is_active', 'is_default'
]
list_filter = ['template_type', 'channel_type', 'is_active', 'is_default']
search_fields = ['name', 'subject_template']
ordering = ['template_type', 'channel_type', 'name']
fieldsets = (
('Basic Information', {
'fields': ('name', 'template_type', 'channel_type')
}),
('Template Content', {
'fields': ('subject_template', 'body_template', 'variables')
}),
('Status', {
'fields': ('is_active', 'is_default')
}),
('Metadata', {
'fields': ('created_by', 'created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
readonly_fields = ['created_at', 'updated_at']