665 lines
33 KiB
HTML
665 lines
33 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}{{ object.name }} - Channel Details{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<!-- Breadcrumb -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="page-title-box d-sm-flex align-items-center justify-content-between">
|
|
<h4 class="mb-sm-0">Channel Details</h4>
|
|
<div class="page-title-right">
|
|
<ol class="breadcrumb m-0">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'communications:dashboard' %}">Communications</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'communications:communication_channel_list' %}">Channels</a></li>
|
|
<li class="breadcrumb-item active">{{ object.name }}</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Main Content -->
|
|
<div class="col-lg-8">
|
|
<!-- Channel Overview -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-{% if object.channel_type == 'EMAIL' %}envelope{% elif object.channel_type == 'SMS' %}sms{% elif object.channel_type == 'PUSH' %}bell{% elif object.channel_type == 'WEBHOOK' %}link{% elif object.channel_type == 'SLACK' %}slack{% elif object.channel_type == 'TEAMS' %}microsoft{% else %}broadcast-tower{% endif %} me-2"></i>
|
|
{{ object.name }}
|
|
</h5>
|
|
<div class="d-flex gap-2">
|
|
<span class="badge bg-{% if object.channel_type == 'EMAIL' %}primary{% elif object.channel_type == 'SMS' %}success{% elif object.channel_type == 'PUSH' %}warning{% elif object.channel_type == 'WEBHOOK' %}info{% elif object.channel_type == 'SLACK' %}secondary{% else %}dark{% endif %} fs-6">
|
|
{{ object.get_channel_type_display }}
|
|
</span>
|
|
<span class="badge bg-{% if object.is_active %}success{% else %}secondary{% endif %} fs-6">
|
|
{% if object.is_active %}Active{% else %}Inactive{% endif %}
|
|
</span>
|
|
<span class="badge bg-{% if object.health_status == 'HEALTHY' %}success{% elif object.health_status == 'WARNING' %}warning{% else %}danger{% endif %} fs-6">
|
|
{{ object.get_health_status_display|default:"Unknown" }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<!-- Channel Description -->
|
|
{% if object.description %}
|
|
<div class="alert alert-light" role="alert">
|
|
<div class="d-flex">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-info-circle fa-lg"></i>
|
|
</div>
|
|
<div class="flex-grow-1 ms-3">
|
|
<p class="mb-0">{{ object.description }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Channel Information -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="table-responsive">
|
|
<table class="table table-borderless">
|
|
<tr>
|
|
<td class="fw-bold text-muted">Channel Type:</td>
|
|
<td>{{ object.get_channel_type_display }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Status:</td>
|
|
<td>
|
|
<div class="d-flex align-items-center">
|
|
<span class="badge bg-{% if object.is_active %}success{% else %}secondary{% endif %} me-2">
|
|
{% if object.is_active %}Active{% else %}Inactive{% endif %}
|
|
</span>
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" {% if object.is_active %}checked{% endif %}
|
|
onchange="toggleChannel(this.checked)">
|
|
</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Health Status:</td>
|
|
<td>
|
|
<span class="badge bg-{% if object.health_status == 'HEALTHY' %}success{% elif object.health_status == 'WARNING' %}warning{% else %}danger{% endif %}">
|
|
{{ object.get_health_status_display|default:"Unknown" }}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Priority:</td>
|
|
<td>
|
|
<span class="badge bg-{% if object.priority == 'HIGH' %}danger{% elif object.priority == 'MEDIUM' %}warning{% else %}secondary{% endif %}">
|
|
{{ object.get_priority_display|default:"Normal" }}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="table-responsive">
|
|
<table class="table table-borderless">
|
|
<tr>
|
|
<td class="fw-bold text-muted">Created:</td>
|
|
<td>{{ object.created_at|date:"M d, Y g:i A" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Last Updated:</td>
|
|
<td>{{ object.updated_at|date:"M d, Y g:i A" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Last Health Check:</td>
|
|
<td>
|
|
{% if object.last_health_check %}
|
|
{{ object.last_health_check|date:"M d, Y g:i A" }}
|
|
<br><small class="text-muted">{{ object.last_health_check|timesince }} ago</small>
|
|
{% else %}
|
|
<span class="text-muted">Never</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Rate Limit:</td>
|
|
<td>
|
|
{% if object.rate_limit %}
|
|
{{ object.rate_limit }} messages/hour
|
|
{% else %}
|
|
<span class="text-muted">No limit</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Configuration Details -->
|
|
<div class="mb-4">
|
|
<h6 class="text-muted mb-2">Configuration:</h6>
|
|
<div class="bg-light p-3 rounded">
|
|
{% if object.channel_type == 'EMAIL' %}
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<strong>SMTP Server:</strong> {{ object.configuration.smtp_host|default:"Not configured" }}<br>
|
|
<strong>Port:</strong> {{ object.configuration.smtp_port|default:"Not configured" }}<br>
|
|
<strong>Security:</strong> {{ object.configuration.smtp_security|default:"None" }}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<strong>From Email:</strong> {{ object.configuration.from_email|default:"Not configured" }}<br>
|
|
<strong>From Name:</strong> {{ object.configuration.from_name|default:"Not configured" }}<br>
|
|
<strong>Authentication:</strong> {% if object.configuration.smtp_username %}Enabled{% else %}Disabled{% endif %}
|
|
</div>
|
|
</div>
|
|
{% elif object.channel_type == 'SMS' %}
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<strong>Provider:</strong> {{ object.configuration.sms_provider|default:"Not configured" }}<br>
|
|
<strong>API Endpoint:</strong> {{ object.configuration.api_endpoint|default:"Not configured" }}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<strong>From Number:</strong> {{ object.configuration.from_number|default:"Not configured" }}<br>
|
|
<strong>API Key:</strong> {% if object.configuration.api_key %}Configured{% else %}Not configured{% endif %}
|
|
</div>
|
|
</div>
|
|
{% elif object.channel_type == 'WEBHOOK' %}
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<strong>URL:</strong> {{ object.configuration.webhook_url|default:"Not configured" }}<br>
|
|
<strong>Method:</strong> {{ object.configuration.http_method|default:"POST" }}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<strong>Content Type:</strong> {{ object.configuration.content_type|default:"application/json" }}<br>
|
|
<strong>Authentication:</strong> {% if object.configuration.auth_header %}Enabled{% else %}Disabled{% endif %}
|
|
</div>
|
|
</div>
|
|
{% elif object.channel_type == 'SLACK' %}
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<strong>Webhook URL:</strong> {% if object.configuration.slack_webhook %}Configured{% else %}Not configured{% endif %}<br>
|
|
<strong>Channel:</strong> {{ object.configuration.slack_channel|default:"#general" }}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<strong>Username:</strong> {{ object.configuration.slack_username|default:"Hospital Bot" }}<br>
|
|
<strong>Icon:</strong> {{ object.configuration.slack_icon|default:":hospital:" }}
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<pre class="mb-0">{{ object.configuration|pprint }}</pre>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Retry Configuration -->
|
|
{% if object.retry_attempts or object.retry_delay %}
|
|
<div class="mb-4">
|
|
<h6 class="text-muted mb-2">Retry Configuration:</h6>
|
|
<div class="card bg-light">
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="table-responsive">
|
|
<table class="table table-borderless table-sm">
|
|
<tr>
|
|
<td class="fw-bold text-muted">Max Attempts:</td>
|
|
<td>{{ object.retry_attempts|default:0 }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Retry Delay:</td>
|
|
<td>{{ object.retry_delay|default:0 }} seconds</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="table-responsive">
|
|
<table class="table table-borderless table-sm">
|
|
<tr>
|
|
<td class="fw-bold text-muted">Backoff Strategy:</td>
|
|
<td>{{ object.backoff_strategy|default:"Linear" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Max Delay:</td>
|
|
<td>{{ object.max_retry_delay|default:"No limit" }}</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Performance Metrics -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-chart-line me-2"></i>
|
|
Performance Metrics
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h4 class="mb-1">{{ object.message_count|default:0 }}</h4>
|
|
<p class="text-muted mb-0">Total Messages</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h4 class="mb-1">{{ object.success_rate|default:0 }}%</h4>
|
|
<p class="text-muted mb-0">Success Rate</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h4 class="mb-1">{{ object.avg_delivery_time|default:0 }}ms</h4>
|
|
<p class="text-muted mb-0">Avg Delivery Time</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h4 class="mb-1">{{ object.failed_count|default:0 }}</h4>
|
|
<p class="text-muted mb-0">Failed Messages</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<hr>
|
|
|
|
<!-- Performance Chart Placeholder -->
|
|
<div class="text-center">
|
|
<canvas id="performanceChart" height="100"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Messages -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-history me-2"></i>
|
|
Recent Messages
|
|
</h5>
|
|
<a href="{% url 'communications:delivery_log_list' %}?channel={{ object.id }}" class="btn btn-sm btn-outline-primary">
|
|
View All Logs
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if recent_messages %}
|
|
<div class="table-responsive">
|
|
<table class="table table-nowrap table-hover mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Message</th>
|
|
<th>Recipient</th>
|
|
<th>Status</th>
|
|
<th>Sent</th>
|
|
<th>Delivery Time</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for message in recent_messages %}
|
|
<tr>
|
|
<td>{{ message.subject|default:message.content|truncatechars:40 }}</td>
|
|
<td>{{ message.recipient|truncatechars:30 }}</td>
|
|
<td>
|
|
<span class="badge bg-{% if message.status == 'DELIVERED' %}success{% elif message.status == 'FAILED' %}danger{% elif message.status == 'PENDING' %}warning{% else %}secondary{% endif %}">
|
|
{{ message.get_status_display }}
|
|
</span>
|
|
</td>
|
|
<td>{{ message.sent_at|date:"M d, g:i A" }}</td>
|
|
<td>
|
|
{% if message.delivery_time %}
|
|
{{ message.delivery_time }}ms
|
|
{% else %}
|
|
<span class="text-muted">-</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<div class="text-center py-4">
|
|
<i class="fas fa-inbox fa-3x text-muted mb-3"></i>
|
|
<h6 class="text-muted">No recent messages</h6>
|
|
<p class="text-muted">Messages sent through this channel will appear here</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sidebar -->
|
|
<div class="col-lg-4">
|
|
<!-- Quick Actions -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-bolt me-2"></i>
|
|
Quick Actions
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-grid gap-2">
|
|
<button class="btn btn-primary" onclick="testChannel()">
|
|
<i class="fas fa-flask me-1"></i>
|
|
Test Channel
|
|
</button>
|
|
<a href="{% url 'communications:communication_channel_update' object.pk %}" class="btn btn-outline-primary">
|
|
<i class="fas fa-edit me-1"></i>
|
|
Edit Channel
|
|
</a>
|
|
<button class="btn btn-outline-success" onclick="checkHealth()">
|
|
<i class="fas fa-heartbeat me-1"></i>
|
|
Check Health
|
|
</button>
|
|
|
|
<hr>
|
|
|
|
{% if object.is_active %}
|
|
<button class="btn btn-outline-warning" onclick="toggleChannel(false)">
|
|
<i class="fas fa-pause me-1"></i>
|
|
Disable Channel
|
|
</button>
|
|
{% else %}
|
|
<button class="btn btn-outline-success" onclick="toggleChannel(true)">
|
|
<i class="fas fa-play me-1"></i>
|
|
Enable Channel
|
|
</button>
|
|
{% endif %}
|
|
|
|
<button class="btn btn-outline-info" onclick="exportConfig()">
|
|
<i class="fas fa-download me-1"></i>
|
|
Export Config
|
|
</button>
|
|
|
|
<hr>
|
|
|
|
<a href="{% url 'communications:communication_channel_delete' object.pk %}" class="btn btn-outline-danger">
|
|
<i class="fas fa-trash me-1"></i>
|
|
Delete Channel
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Channel Statistics -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-chart-bar me-2"></i>
|
|
Channel Statistics
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-borderless table-sm">
|
|
<tr>
|
|
<td class="fw-bold text-muted">Messages Today:</td>
|
|
<td>{{ object.messages_today|default:0 }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Messages This Week:</td>
|
|
<td>{{ object.messages_week|default:0 }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Messages This Month:</td>
|
|
<td>{{ object.messages_month|default:0 }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Error Rate:</td>
|
|
<td>{{ object.error_rate|default:0 }}%</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Avg Response Time:</td>
|
|
<td>{{ object.avg_response_time|default:0 }}ms</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Uptime:</td>
|
|
<td>{{ object.uptime_percentage|default:0 }}%</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Health Status -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-heartbeat me-2"></i>
|
|
Health Status
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div class="avatar-sm me-3">
|
|
<div class="avatar-title bg-soft-{% if object.health_status == 'HEALTHY' %}success{% elif object.health_status == 'WARNING' %}warning{% else %}danger{% endif %} text-{% if object.health_status == 'HEALTHY' %}success{% elif object.health_status == 'WARNING' %}warning{% else %}danger{% endif %} rounded">
|
|
<i class="fas fa-{% if object.health_status == 'HEALTHY' %}check-circle{% elif object.health_status == 'WARNING' %}exclamation-triangle{% else %}times-circle{% endif %}"></i>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<h6 class="mb-0">{{ object.get_health_status_display|default:"Unknown" }}</h6>
|
|
<small class="text-muted">
|
|
{% if object.last_health_check %}
|
|
Last checked {{ object.last_health_check|timesince }} ago
|
|
{% else %}
|
|
Never checked
|
|
{% endif %}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
{% if object.health_details %}
|
|
<div class="bg-light p-2 rounded">
|
|
<small class="text-muted">{{ object.health_details }}</small>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="mt-3">
|
|
<button class="btn btn-sm btn-outline-primary" onclick="checkHealth()">
|
|
<i class="fas fa-sync-alt me-1"></i>
|
|
Check Now
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Configuration Summary -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-cog me-2"></i>
|
|
Configuration Summary
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-borderless table-sm">
|
|
<tr>
|
|
<td class="fw-bold text-muted">Type:</td>
|
|
<td>{{ object.get_channel_type_display }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Priority:</td>
|
|
<td>{{ object.get_priority_display|default:"Normal" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Rate Limit:</td>
|
|
<td>
|
|
{% if object.rate_limit %}
|
|
{{ object.rate_limit }}/hour
|
|
{% else %}
|
|
No limit
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Retry Attempts:</td>
|
|
<td>{{ object.retry_attempts|default:0 }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold text-muted">Timeout:</td>
|
|
<td>{{ object.timeout|default:30 }}s</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
<script>
|
|
// Performance Chart
|
|
const ctx = document.getElementById('performanceChart').getContext('2d');
|
|
const performanceChart = new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
|
|
datasets: [{
|
|
label: 'Messages Sent',
|
|
data: [12, 19, 3, 5, 2, 3, 7],
|
|
borderColor: 'rgb(75, 192, 192)',
|
|
backgroundColor: 'rgba(75, 192, 192, 0.1)',
|
|
tension: 0.1
|
|
}, {
|
|
label: 'Success Rate %',
|
|
data: [95, 98, 92, 96, 99, 94, 97],
|
|
borderColor: 'rgb(255, 99, 132)',
|
|
backgroundColor: 'rgba(255, 99, 132, 0.1)',
|
|
tension: 0.1,
|
|
yAxisID: 'y1'
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
plugins: {
|
|
legend: {
|
|
position: 'top',
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
type: 'linear',
|
|
display: true,
|
|
position: 'left',
|
|
},
|
|
y1: {
|
|
type: 'linear',
|
|
display: true,
|
|
position: 'right',
|
|
grid: {
|
|
drawOnChartArea: false,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
function toggleChannel(activate) {
|
|
const action = activate ? 'enable' : 'disable';
|
|
|
|
fetch(`{% url 'communications:communication_channel_detail' object.pk %}toggle/`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ active: activate })
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
location.reload();
|
|
} else {
|
|
alert(`Error ${action}ing channel: ` + data.error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function testChannel() {
|
|
if (confirm('Send a test message through this channel?')) {
|
|
fetch(`{% url 'communications:communication_channel_detail' object.pk %}test/`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,
|
|
'Content-Type': 'application/json',
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
alert(`Test message sent successfully!\n\nDelivery time: ${data.delivery_time}ms\nStatus: ${data.status}\nMessage ID: ${data.message_id}`);
|
|
} else {
|
|
alert('Test failed: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function checkHealth() {
|
|
fetch(`{% url 'communications:communication_channel_detail' object.pk %}health/`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,
|
|
'Content-Type': 'application/json',
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
alert(`Health check completed!\n\nStatus: ${data.health_status}\nResponse time: ${data.response_time}ms\nDetails: ${data.details || 'No additional details'}`);
|
|
location.reload();
|
|
} else {
|
|
alert('Health check failed: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function exportConfig() {
|
|
window.open(`{% url 'communications:communication_channel_detail' object.pk %}export/`, '_blank');
|
|
}
|
|
|
|
// Auto-refresh health status
|
|
setInterval(function() {
|
|
fetch(`{% url 'communications:communication_channel_detail' object.pk %}health-status/`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
// Update health status badge
|
|
const healthBadges = document.querySelectorAll('.badge:contains("' + data.old_status + '")');
|
|
healthBadges.forEach(badge => {
|
|
badge.className = `badge bg-${data.health_status === 'HEALTHY' ? 'success' : data.health_status === 'WARNING' ? 'warning' : 'danger'} fs-6`;
|
|
badge.textContent = data.health_status;
|
|
});
|
|
}
|
|
});
|
|
}, 60000); // Update every minute
|
|
</script>
|
|
{% endblock %}
|
|
|