280 lines
9.5 KiB
Python
280 lines
9.5 KiB
Python
"""
|
|
Admin configuration for Collaboration & War Rooms module
|
|
"""
|
|
from django.contrib import admin
|
|
from django.utils.html import format_html
|
|
|
|
from .models import (
|
|
WarRoom, ConferenceBridge, IncidentCommandRole,
|
|
TimelineEvent, WarRoomMessage, IncidentDecision
|
|
)
|
|
|
|
|
|
@admin.register(WarRoom)
|
|
class WarRoomAdmin(admin.ModelAdmin):
|
|
"""Admin interface for WarRoom model"""
|
|
|
|
list_display = [
|
|
'name', 'incident_title', 'status', 'privacy_level',
|
|
'message_count', 'active_participants', 'created_at'
|
|
]
|
|
list_filter = ['status', 'privacy_level', 'created_at']
|
|
search_fields = ['name', 'description', 'incident__title']
|
|
readonly_fields = ['id', 'created_at', 'updated_at', 'message_count', 'last_activity']
|
|
|
|
fieldsets = (
|
|
('Basic Information', {
|
|
'fields': ('id', 'name', 'description', 'incident')
|
|
}),
|
|
('Configuration', {
|
|
'fields': ('status', 'privacy_level', 'required_clearance_level')
|
|
}),
|
|
('Integrations', {
|
|
'fields': ('slack_channel_id', 'teams_channel_id', 'discord_channel_id'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Access Control', {
|
|
'fields': ('allowed_users',),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Activity Tracking', {
|
|
'fields': ('message_count', 'last_activity', 'active_participants'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Metadata', {
|
|
'fields': ('created_by', 'created_at', 'updated_at', 'archived_at'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
)
|
|
|
|
def incident_title(self, obj):
|
|
"""Display incident title"""
|
|
return obj.incident.title
|
|
incident_title.short_description = 'Incident'
|
|
|
|
|
|
@admin.register(ConferenceBridge)
|
|
class ConferenceBridgeAdmin(admin.ModelAdmin):
|
|
"""Admin interface for ConferenceBridge model"""
|
|
|
|
list_display = [
|
|
'name', 'incident_title', 'bridge_type', 'status',
|
|
'scheduled_start', 'participant_count'
|
|
]
|
|
list_filter = ['bridge_type', 'status', 'recording_enabled', 'transcription_enabled']
|
|
search_fields = ['name', 'description', 'incident__title']
|
|
readonly_fields = ['id', 'created_at', 'updated_at', 'actual_start', 'actual_end']
|
|
|
|
fieldsets = (
|
|
('Basic Information', {
|
|
'fields': ('id', 'name', 'description', 'incident', 'war_room')
|
|
}),
|
|
('Bridge Configuration', {
|
|
'fields': ('bridge_type', 'status', 'integration_config')
|
|
}),
|
|
('Meeting Details', {
|
|
'fields': ('meeting_id', 'meeting_url', 'dial_in_number', 'access_code')
|
|
}),
|
|
('Schedule', {
|
|
'fields': ('scheduled_start', 'scheduled_end', 'actual_start', 'actual_end')
|
|
}),
|
|
('Participants', {
|
|
'fields': ('invited_participants', 'active_participants', 'max_participants'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Recording & Transcription', {
|
|
'fields': ('recording_enabled', 'recording_url', 'transcription_enabled', 'transcription_url'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Metadata', {
|
|
'fields': ('created_by', 'created_at', 'updated_at'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
)
|
|
|
|
def incident_title(self, obj):
|
|
"""Display incident title"""
|
|
return obj.incident.title
|
|
incident_title.short_description = 'Incident'
|
|
|
|
def participant_count(self, obj):
|
|
"""Display participant count"""
|
|
return obj.invited_participants.count()
|
|
participant_count.short_description = 'Participants'
|
|
|
|
|
|
@admin.register(IncidentCommandRole)
|
|
class IncidentCommandRoleAdmin(admin.ModelAdmin):
|
|
"""Admin interface for IncidentCommandRole model"""
|
|
|
|
list_display = [
|
|
'role_type', 'incident_title', 'assigned_user', 'status',
|
|
'decisions_made', 'assigned_at'
|
|
]
|
|
list_filter = ['role_type', 'status', 'assigned_at']
|
|
search_fields = ['incident__title', 'assigned_user__username']
|
|
readonly_fields = [
|
|
'id', 'assigned_at', 'reassigned_at', 'reassigned_by',
|
|
'decisions_made', 'communications_sent', 'last_activity',
|
|
'created_at', 'updated_at'
|
|
]
|
|
|
|
fieldsets = (
|
|
('Basic Information', {
|
|
'fields': ('id', 'incident', 'war_room', 'role_type', 'assigned_user', 'status')
|
|
}),
|
|
('Role Configuration', {
|
|
'fields': ('responsibilities', 'decision_authority'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Assignment Tracking', {
|
|
'fields': ('assigned_at', 'reassigned_at', 'reassigned_by', 'assignment_notes'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Performance Tracking', {
|
|
'fields': ('decisions_made', 'communications_sent', 'last_activity'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Metadata', {
|
|
'fields': ('created_by', 'created_at', 'updated_at'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
)
|
|
|
|
def incident_title(self, obj):
|
|
"""Display incident title"""
|
|
return obj.incident.title
|
|
incident_title.short_description = 'Incident'
|
|
|
|
|
|
@admin.register(TimelineEvent)
|
|
class TimelineEventAdmin(admin.ModelAdmin):
|
|
"""Admin interface for TimelineEvent model"""
|
|
|
|
list_display = [
|
|
'event_time', 'title', 'incident_title', 'event_type',
|
|
'source_type', 'is_critical_event'
|
|
]
|
|
list_filter = ['event_type', 'source_type', 'is_critical_event', 'event_time']
|
|
search_fields = ['title', 'description', 'incident__title']
|
|
readonly_fields = ['id', 'created_at']
|
|
|
|
fieldsets = (
|
|
('Basic Information', {
|
|
'fields': ('id', 'incident', 'event_type', 'title', 'description', 'source_type')
|
|
}),
|
|
('Timing', {
|
|
'fields': ('event_time', 'created_at')
|
|
}),
|
|
('Related Objects', {
|
|
'fields': (
|
|
'related_user', 'related_runbook_execution', 'related_auto_remediation',
|
|
'related_sla_instance', 'related_escalation', 'related_war_room',
|
|
'related_conference', 'related_command_role'
|
|
),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Event Data', {
|
|
'fields': ('event_data', 'tags'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Postmortem', {
|
|
'fields': ('is_critical_event', 'postmortem_notes'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Metadata', {
|
|
'fields': ('created_by',),
|
|
'classes': ('collapse',)
|
|
}),
|
|
)
|
|
|
|
def incident_title(self, obj):
|
|
"""Display incident title"""
|
|
return obj.incident.title
|
|
incident_title.short_description = 'Incident'
|
|
|
|
|
|
@admin.register(WarRoomMessage)
|
|
class WarRoomMessageAdmin(admin.ModelAdmin):
|
|
"""Admin interface for WarRoomMessage model"""
|
|
|
|
list_display = [
|
|
'sender_name', 'war_room_name', 'message_type', 'content_preview', 'created_at'
|
|
]
|
|
list_filter = ['message_type', 'is_edited', 'created_at']
|
|
search_fields = ['content', 'sender_name', 'war_room__name']
|
|
readonly_fields = ['id', 'created_at', 'updated_at', 'is_edited', 'edited_at']
|
|
|
|
fieldsets = (
|
|
('Basic Information', {
|
|
'fields': ('id', 'war_room', 'message_type', 'content')
|
|
}),
|
|
('Sender Information', {
|
|
'fields': ('sender', 'sender_name')
|
|
}),
|
|
('Message Metadata', {
|
|
'fields': ('is_edited', 'edited_at', 'reply_to'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Integration Data', {
|
|
'fields': ('external_message_id', 'external_data'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Timestamps', {
|
|
'fields': ('created_at', 'updated_at'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
)
|
|
|
|
def war_room_name(self, obj):
|
|
"""Display war room name"""
|
|
return obj.war_room.name
|
|
war_room_name.short_description = 'War Room'
|
|
|
|
def content_preview(self, obj):
|
|
"""Display content preview"""
|
|
return obj.content[:50] + '...' if len(obj.content) > 50 else obj.content
|
|
content_preview.short_description = 'Content Preview'
|
|
|
|
|
|
@admin.register(IncidentDecision)
|
|
class IncidentDecisionAdmin(admin.ModelAdmin):
|
|
"""Admin interface for IncidentDecision model"""
|
|
|
|
list_display = [
|
|
'title', 'incident_title', 'decision_type', 'status',
|
|
'approved_by', 'implemented_by', 'created_at'
|
|
]
|
|
list_filter = ['decision_type', 'status', 'requires_approval', 'created_at']
|
|
search_fields = ['title', 'description', 'incident__title']
|
|
readonly_fields = [
|
|
'id', 'approved_by', 'approved_at', 'implemented_at',
|
|
'implemented_by', 'created_at', 'updated_at'
|
|
]
|
|
|
|
fieldsets = (
|
|
('Basic Information', {
|
|
'fields': ('id', 'incident', 'command_role', 'decision_type', 'title', 'description', 'rationale')
|
|
}),
|
|
('Decision Status', {
|
|
'fields': ('status', 'requires_approval', 'approved_by', 'approved_at')
|
|
}),
|
|
('Implementation', {
|
|
'fields': ('implementation_notes', 'implemented_at', 'implemented_by'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Impact Tracking', {
|
|
'fields': ('impact_assessment', 'success_metrics'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
('Timestamps', {
|
|
'fields': ('created_at', 'updated_at'),
|
|
'classes': ('collapse',)
|
|
}),
|
|
)
|
|
|
|
def incident_title(self, obj):
|
|
"""Display incident title"""
|
|
return obj.incident.title
|
|
incident_title.short_description = 'Incident'
|