743 lines
43 KiB
HTML
743 lines
43 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}{% if object %}Edit Channel - {{ object.name }}{% else %}Add New Channel{% endif %}{% 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">{% if object %}Edit Channel{% else %}Add New Channel{% endif %}</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">{% if object %}Edit{% else %}Add{% endif %}</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Main Form -->
|
|
<div class="col-lg-8">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-{% if object %}edit{% else %}plus{% endif %} me-2"></i>
|
|
Channel Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="post" id="channelForm">
|
|
{% csrf_token %}
|
|
|
|
<!-- Basic Information -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
{{ form.name }}
|
|
<label for="{{ form.name.id_for_label }}">Channel Name *</label>
|
|
{% if form.name.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.name.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
{{ form.channel_type }}
|
|
<label for="{{ form.channel_type.id_for_label }}">Channel Type *</label>
|
|
{% if form.channel_type.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.channel_type.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="form-floating mb-3">
|
|
{{ form.description }}
|
|
<label for="{{ form.description.id_for_label }}">Description</label>
|
|
{% if form.description.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.description.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Status and Priority -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="form-check form-switch mb-3">
|
|
{{ form.is_active }}
|
|
<label class="form-check-label" for="{{ form.is_active.id_for_label }}">
|
|
Active Channel
|
|
</label>
|
|
{% if form.is_active.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.is_active.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
{{ form.priority }}
|
|
<label for="{{ form.priority.id_for_label }}">Priority</label>
|
|
{% if form.priority.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.priority.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Rate Limiting -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
{{ form.rate_limit }}
|
|
<label for="{{ form.rate_limit.id_for_label }}">Rate Limit (messages/hour)</label>
|
|
{% if form.rate_limit.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.rate_limit.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
{{ form.timeout }}
|
|
<label for="{{ form.timeout.id_for_label }}">Timeout (seconds)</label>
|
|
{% if form.timeout.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.timeout.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Retry Configuration -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h6 class="card-title mb-0">Retry Configuration</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<div class="form-floating mb-3">
|
|
{{ form.retry_attempts }}
|
|
<label for="{{ form.retry_attempts.id_for_label }}">Max Retry Attempts</label>
|
|
{% if form.retry_attempts.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.retry_attempts.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-floating mb-3">
|
|
{{ form.retry_delay }}
|
|
<label for="{{ form.retry_delay.id_for_label }}">Retry Delay (seconds)</label>
|
|
{% if form.retry_delay.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.retry_delay.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-floating mb-3">
|
|
{{ form.backoff_strategy }}
|
|
<label for="{{ form.backoff_strategy.id_for_label }}">Backoff Strategy</label>
|
|
{% if form.backoff_strategy.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.backoff_strategy.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Channel-Specific Configuration -->
|
|
<div class="card mb-4" id="configurationCard">
|
|
<div class="card-header">
|
|
<h6 class="card-title mb-0">Channel Configuration</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<!-- Email Configuration -->
|
|
<div id="emailConfig" class="channel-config" style="display: none;">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="text" class="form-control" id="smtp_host" name="smtp_host"
|
|
value="{{ form.configuration.smtp_host.value|default:'' }}">
|
|
<label for="smtp_host">SMTP Host *</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="number" class="form-control" id="smtp_port" name="smtp_port"
|
|
value="{{ form.configuration.smtp_port.value|default:'587' }}">
|
|
<label for="smtp_port">SMTP Port *</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="email" class="form-control" id="from_email" name="from_email"
|
|
value="{{ form.configuration.from_email.value|default:'' }}">
|
|
<label for="from_email">From Email *</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="text" class="form-control" id="from_name" name="from_name"
|
|
value="{{ form.configuration.from_name.value|default:'' }}">
|
|
<label for="from_name">From Name</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="text" class="form-control" id="smtp_username" name="smtp_username"
|
|
value="{{ form.configuration.smtp_username.value|default:'' }}">
|
|
<label for="smtp_username">SMTP Username</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="password" class="form-control" id="smtp_password" name="smtp_password">
|
|
<label for="smtp_password">SMTP Password</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<select class="form-select" id="smtp_security" name="smtp_security">
|
|
<option value="">None</option>
|
|
<option value="TLS">TLS</option>
|
|
<option value="SSL">SSL</option>
|
|
</select>
|
|
<label for="smtp_security">Security</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SMS Configuration -->
|
|
<div id="smsConfig" class="channel-config" style="display: none;">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<select class="form-select" id="sms_provider" name="sms_provider">
|
|
<option value="">Select Provider</option>
|
|
<option value="twilio">Twilio</option>
|
|
<option value="aws_sns">AWS SNS</option>
|
|
<option value="nexmo">Nexmo</option>
|
|
<option value="custom">Custom</option>
|
|
</select>
|
|
<label for="sms_provider">SMS Provider *</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="text" class="form-control" id="from_number" name="from_number"
|
|
value="{{ form.configuration.from_number.value|default:'' }}">
|
|
<label for="from_number">From Number *</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="text" class="form-control" id="api_key" name="api_key"
|
|
value="{{ form.configuration.api_key.value|default:'' }}">
|
|
<label for="api_key">API Key *</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="password" class="form-control" id="api_secret" name="api_secret">
|
|
<label for="api_secret">API Secret</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="form-floating mb-3">
|
|
<input type="url" class="form-control" id="api_endpoint" name="api_endpoint"
|
|
value="{{ form.configuration.api_endpoint.value|default:'' }}">
|
|
<label for="api_endpoint">API Endpoint</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Webhook Configuration -->
|
|
<div id="webhookConfig" class="channel-config" style="display: none;">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="form-floating mb-3">
|
|
<input type="url" class="form-control" id="webhook_url" name="webhook_url"
|
|
value="{{ form.configuration.webhook_url.value|default:'' }}">
|
|
<label for="webhook_url">Webhook URL *</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<select class="form-select" id="http_method" name="http_method">
|
|
<option value="POST">POST</option>
|
|
<option value="PUT">PUT</option>
|
|
<option value="PATCH">PATCH</option>
|
|
</select>
|
|
<label for="http_method">HTTP Method</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<select class="form-select" id="content_type" name="content_type">
|
|
<option value="application/json">application/json</option>
|
|
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
|
|
<option value="text/plain">text/plain</option>
|
|
</select>
|
|
<label for="content_type">Content Type</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="form-floating mb-3">
|
|
<textarea class="form-control" id="custom_headers" name="custom_headers" style="height: 100px;">{{ form.configuration.custom_headers.value|default:'' }}</textarea>
|
|
<label for="custom_headers">Custom Headers (JSON format)</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="form-floating mb-3">
|
|
<input type="text" class="form-control" id="auth_header" name="auth_header"
|
|
value="{{ form.configuration.auth_header.value|default:'' }}">
|
|
<label for="auth_header">Authorization Header</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Slack Configuration -->
|
|
<div id="slackConfig" class="channel-config" style="display: none;">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="form-floating mb-3">
|
|
<input type="url" class="form-control" id="slack_webhook" name="slack_webhook"
|
|
value="{{ form.configuration.slack_webhook.value|default:'' }}">
|
|
<label for="slack_webhook">Slack Webhook URL *</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="text" class="form-control" id="slack_channel" name="slack_channel"
|
|
value="{{ form.configuration.slack_channel.value|default:'#general' }}">
|
|
<label for="slack_channel">Channel</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="text" class="form-control" id="slack_username" name="slack_username"
|
|
value="{{ form.configuration.slack_username.value|default:'Hospital Bot' }}">
|
|
<label for="slack_username">Username</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="text" class="form-control" id="slack_icon" name="slack_icon"
|
|
value="{{ form.configuration.slack_icon.value|default:':hospital:' }}">
|
|
<label for="slack_icon">Icon Emoji</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Teams Configuration -->
|
|
<div id="teamsConfig" class="channel-config" style="display: none;">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="form-floating mb-3">
|
|
<input type="url" class="form-control" id="teams_webhook" name="teams_webhook"
|
|
value="{{ form.configuration.teams_webhook.value|default:'' }}">
|
|
<label for="teams_webhook">Teams Webhook URL *</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="text" class="form-control" id="teams_title" name="teams_title"
|
|
value="{{ form.configuration.teams_title.value|default:'Hospital Notification' }}">
|
|
<label for="teams_title">Default Title</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="color" class="form-control form-control-color" id="teams_color" name="teams_color"
|
|
value="{{ form.configuration.teams_color.value|default:'#0078d4' }}">
|
|
<label for="teams_color">Theme Color</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Push Notification Configuration -->
|
|
<div id="pushConfig" class="channel-config" style="display: none;">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<select class="form-select" id="push_provider" name="push_provider">
|
|
<option value="">Select Provider</option>
|
|
<option value="fcm">Firebase Cloud Messaging</option>
|
|
<option value="apns">Apple Push Notification</option>
|
|
<option value="web_push">Web Push</option>
|
|
</select>
|
|
<label for="push_provider">Push Provider *</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-floating mb-3">
|
|
<input type="text" class="form-control" id="server_key" name="server_key"
|
|
value="{{ form.configuration.server_key.value|default:'' }}">
|
|
<label for="server_key">Server Key *</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="form-floating mb-3">
|
|
<textarea class="form-control" id="service_account" name="service_account" style="height: 150px;">{{ form.configuration.service_account.value|default:'' }}</textarea>
|
|
<label for="service_account">Service Account JSON</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Form Actions -->
|
|
<div class="d-flex justify-content-between">
|
|
<a href="{% url 'communications:communication_channel_list' %}" class="btn btn-outline-secondary">
|
|
<i class="fas fa-arrow-left me-1"></i>
|
|
Cancel
|
|
</a>
|
|
<div>
|
|
<button type="button" class="btn btn-outline-primary me-2" onclick="testConfiguration()">
|
|
<i class="fas fa-flask me-1"></i>
|
|
Test Configuration
|
|
</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-save me-1"></i>
|
|
{% if object %}Update Channel{% else %}Create Channel{% endif %}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Help Sidebar -->
|
|
<div class="col-lg-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-question-circle me-2"></i>
|
|
Help & Guidelines
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="accordion" id="helpAccordion">
|
|
<!-- Email Help -->
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header" id="emailHelp">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#emailHelpContent">
|
|
Email Configuration
|
|
</button>
|
|
</h2>
|
|
<div id="emailHelpContent" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
|
|
<div class="accordion-body">
|
|
<ul class="list-unstyled">
|
|
<li><strong>SMTP Host:</strong> Your email provider's SMTP server</li>
|
|
<li><strong>Port:</strong> Usually 587 for TLS, 465 for SSL</li>
|
|
<li><strong>Security:</strong> Use TLS for modern servers</li>
|
|
<li><strong>Authentication:</strong> Required for most providers</li>
|
|
</ul>
|
|
<div class="alert alert-info alert-sm">
|
|
<small><strong>Common Providers:</strong><br>
|
|
Gmail: smtp.gmail.com:587<br>
|
|
Outlook: smtp-mail.outlook.com:587</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SMS Help -->
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header" id="smsHelp">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#smsHelpContent">
|
|
SMS Configuration
|
|
</button>
|
|
</h2>
|
|
<div id="smsHelpContent" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
|
|
<div class="accordion-body">
|
|
<ul class="list-unstyled">
|
|
<li><strong>Provider:</strong> Choose your SMS service provider</li>
|
|
<li><strong>From Number:</strong> Your registered sender number</li>
|
|
<li><strong>API Key:</strong> Your provider's API key</li>
|
|
<li><strong>API Secret:</strong> Additional authentication if required</li>
|
|
</ul>
|
|
<div class="alert alert-warning alert-sm">
|
|
<small><strong>Note:</strong> Ensure your sender number is verified with your provider</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Webhook Help -->
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header" id="webhookHelp">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#webhookHelpContent">
|
|
Webhook Configuration
|
|
</button>
|
|
</h2>
|
|
<div id="webhookHelpContent" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
|
|
<div class="accordion-body">
|
|
<ul class="list-unstyled">
|
|
<li><strong>URL:</strong> The endpoint to receive notifications</li>
|
|
<li><strong>Method:</strong> HTTP method (usually POST)</li>
|
|
<li><strong>Content Type:</strong> Format of the payload</li>
|
|
<li><strong>Headers:</strong> Additional HTTP headers in JSON format</li>
|
|
</ul>
|
|
<div class="alert alert-info alert-sm">
|
|
<small><strong>Example Headers:</strong><br>
|
|
{"Authorization": "Bearer token", "X-API-Key": "key"}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Rate Limiting Help -->
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header" id="rateLimitHelp">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#rateLimitHelpContent">
|
|
Rate Limiting & Retries
|
|
</button>
|
|
</h2>
|
|
<div id="rateLimitHelpContent" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
|
|
<div class="accordion-body">
|
|
<ul class="list-unstyled">
|
|
<li><strong>Rate Limit:</strong> Maximum messages per hour</li>
|
|
<li><strong>Retry Attempts:</strong> Number of retry attempts on failure</li>
|
|
<li><strong>Retry Delay:</strong> Initial delay between retries</li>
|
|
<li><strong>Backoff:</strong> How delay increases with each retry</li>
|
|
</ul>
|
|
<div class="alert alert-success alert-sm">
|
|
<small><strong>Recommended:</strong> 3 retries with exponential backoff</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Test Results -->
|
|
<div class="card" id="testResultsCard" style="display: none;">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-flask me-2"></i>
|
|
Test Results
|
|
</h5>
|
|
</div>
|
|
<div class="card-body" id="testResults">
|
|
<!-- Test results will be displayed here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const channelTypeSelect = document.getElementById('{{ form.channel_type.id_for_label }}');
|
|
|
|
// Show/hide configuration based on channel type
|
|
function toggleConfiguration() {
|
|
const channelType = channelTypeSelect.value;
|
|
const configs = document.querySelectorAll('.channel-config');
|
|
|
|
configs.forEach(config => {
|
|
config.style.display = 'none';
|
|
});
|
|
|
|
if (channelType) {
|
|
const configId = channelType.toLowerCase() + 'Config';
|
|
const configElement = document.getElementById(configId);
|
|
if (configElement) {
|
|
configElement.style.display = 'block';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize configuration display
|
|
toggleConfiguration();
|
|
|
|
// Listen for channel type changes
|
|
channelTypeSelect.addEventListener('change', toggleConfiguration);
|
|
});
|
|
|
|
function testConfiguration() {
|
|
const form = document.getElementById('channelForm');
|
|
const formData = new FormData(form);
|
|
|
|
// Show loading state
|
|
const testButton = event.target;
|
|
const originalText = testButton.innerHTML;
|
|
testButton.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Testing...';
|
|
testButton.disabled = true;
|
|
|
|
fetch('{% if object %}{% url "communications:communication_channel_update" object.pk %}{% else %}{% url "communications:communication_channel_create" %}{% endif %}test/', {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,
|
|
},
|
|
body: formData
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
// Show test results
|
|
const testResultsCard = document.getElementById('testResultsCard');
|
|
const testResults = document.getElementById('testResults');
|
|
|
|
if (data.success) {
|
|
testResults.innerHTML = `
|
|
<div class="alert alert-success" role="alert">
|
|
<div class="d-flex">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-check-circle fa-lg"></i>
|
|
</div>
|
|
<div class="flex-grow-1 ms-3">
|
|
<h6 class="alert-heading">Test Successful!</h6>
|
|
<p class="mb-1">Configuration is valid and working.</p>
|
|
<hr>
|
|
<div class="mb-0">
|
|
<small><strong>Response Time:</strong> ${data.response_time}ms</small><br>
|
|
<small><strong>Status:</strong> ${data.status}</small>
|
|
${data.message_id ? `<br><small><strong>Message ID:</strong> ${data.message_id}</small>` : ''}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
} else {
|
|
testResults.innerHTML = `
|
|
<div class="alert alert-danger" role="alert">
|
|
<div class="d-flex">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-times-circle fa-lg"></i>
|
|
</div>
|
|
<div class="flex-grow-1 ms-3">
|
|
<h6 class="alert-heading">Test Failed</h6>
|
|
<p class="mb-1">${data.error}</p>
|
|
${data.details ? `<hr><div class="mb-0"><small>${data.details}</small></div>` : ''}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
testResultsCard.style.display = 'block';
|
|
testResultsCard.scrollIntoView({ behavior: 'smooth' });
|
|
})
|
|
.catch(error => {
|
|
console.error('Test error:', error);
|
|
const testResults = document.getElementById('testResults');
|
|
testResults.innerHTML = `
|
|
<div class="alert alert-danger" role="alert">
|
|
<div class="d-flex">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-times-circle fa-lg"></i>
|
|
</div>
|
|
<div class="flex-grow-1 ms-3">
|
|
<h6 class="alert-heading">Test Error</h6>
|
|
<p class="mb-0">An error occurred while testing the configuration.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
document.getElementById('testResultsCard').style.display = 'block';
|
|
})
|
|
.finally(() => {
|
|
// Restore button state
|
|
testButton.innerHTML = originalText;
|
|
testButton.disabled = false;
|
|
});
|
|
}
|
|
|
|
// Form validation
|
|
document.getElementById('channelForm').addEventListener('submit', function(e) {
|
|
const channelType = document.getElementById('{{ form.channel_type.id_for_label }}').value;
|
|
let isValid = true;
|
|
let errorMessage = '';
|
|
|
|
// Channel-specific validation
|
|
if (channelType === 'EMAIL') {
|
|
const smtpHost = document.getElementById('smtp_host').value;
|
|
const fromEmail = document.getElementById('from_email').value;
|
|
|
|
if (!smtpHost) {
|
|
isValid = false;
|
|
errorMessage = 'SMTP Host is required for email channels.';
|
|
} else if (!fromEmail) {
|
|
isValid = false;
|
|
errorMessage = 'From Email is required for email channels.';
|
|
}
|
|
} else if (channelType === 'SMS') {
|
|
const provider = document.getElementById('sms_provider').value;
|
|
const apiKey = document.getElementById('api_key').value;
|
|
|
|
if (!provider) {
|
|
isValid = false;
|
|
errorMessage = 'SMS Provider is required for SMS channels.';
|
|
} else if (!apiKey) {
|
|
isValid = false;
|
|
errorMessage = 'API Key is required for SMS channels.';
|
|
}
|
|
} else if (channelType === 'WEBHOOK') {
|
|
const webhookUrl = document.getElementById('webhook_url').value;
|
|
|
|
if (!webhookUrl) {
|
|
isValid = false;
|
|
errorMessage = 'Webhook URL is required for webhook channels.';
|
|
}
|
|
} else if (channelType === 'SLACK') {
|
|
const slackWebhook = document.getElementById('slack_webhook').value;
|
|
|
|
if (!slackWebhook) {
|
|
isValid = false;
|
|
errorMessage = 'Slack Webhook URL is required for Slack channels.';
|
|
}
|
|
}
|
|
|
|
if (!isValid) {
|
|
e.preventDefault();
|
|
alert(errorMessage);
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|
|
|