2025-08-12 13:33:25 +03:00

537 lines
25 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}{% if object %}Edit{% else %}Add{% endif %} API Endpoint - Integration{% endblock %}
{% block content %}
<!-- BEGIN breadcrumb -->
<ol class="breadcrumb float-xl-end">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
<li class="breadcrumb-item"><a href="{% url 'integration:dashboard' %}">Integration</a></li>
<li class="breadcrumb-item"><a href="{% url 'integration:api_endpoint_list' %}">API Endpoints</a></li>
<li class="breadcrumb-item active">{% if object %}Edit{% else %}Add{% endif %} Endpoint</li>
</ol>
<!-- END breadcrumb -->
<!-- BEGIN page-header -->
<h1 class="page-header">
{% if object %}Edit API Endpoint{% else %}Add API Endpoint{% endif %}
<small>{% if object %}{{ object.name }}{% else %}External System Integration{% endif %}</small>
</h1>
<!-- END page-header -->
<div class="row">
<div class="col-xl-8">
<!-- BEGIN panel -->
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">Endpoint Configuration</h4>
<div class="panel-heading-btn">
<button type="button" class="btn btn-xs btn-info me-2" onclick="testConnection()">
<i class="fa fa-play"></i> Test
</button>
<button type="button" class="btn btn-xs btn-secondary me-2" onclick="saveDraft()">
<i class="fa fa-save"></i> Save Draft
</button>
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
<form method="post" id="endpoint-form">
{% 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 }}">Endpoint Name <span class="text-danger">*</span></label>
{% if form.name.help_text %}
<div class="form-text">{{ form.name.help_text }}</div>
{% endif %}
{% 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.external_system }}
<label for="{{ form.external_system.id_for_label }}">External System <span class="text-danger">*</span></label>
{% if form.external_system.errors %}
<div class="invalid-feedback d-block">{{ form.external_system.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
<div class="mb-3">
<label class="form-label">Description</label>
{{ form.description }}
{% if form.description.help_text %}
<div class="form-text">{{ form.description.help_text }}</div>
{% endif %}
{% if form.description.errors %}
<div class="invalid-feedback d-block">{{ form.description.errors.0 }}</div>
{% endif %}
</div>
<!-- Request Configuration -->
<h6 class="border-bottom pb-2 mb-3">Request Configuration</h6>
<div class="row mb-3">
<div class="col-md-8">
<div class="form-floating">
{{ form.url }}
<label for="{{ form.url.id_for_label }}">Endpoint URL <span class="text-danger">*</span></label>
{% if form.url.help_text %}
<div class="form-text">{{ form.url.help_text }}</div>
{% endif %}
{% if form.url.errors %}
<div class="invalid-feedback d-block">{{ form.url.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating">
{{ form.method }}
<label for="{{ form.method.id_for_label }}">HTTP Method <span class="text-danger">*</span></label>
{% if form.method.errors %}
<div class="invalid-feedback d-block">{{ form.method.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-4">
<div class="form-floating">
{{ 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 class="col-md-4">
<div class="form-floating">
{{ form.retry_count }}
<label for="{{ form.retry_count.id_for_label }}">Retry Count</label>
{% if form.retry_count.errors %}
<div class="invalid-feedback d-block">{{ form.retry_count.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating">
{{ form.content_type }}
<label for="{{ form.content_type.id_for_label }}">Content Type</label>
{% if form.content_type.errors %}
<div class="invalid-feedback d-block">{{ form.content_type.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
<!-- Authentication -->
<h6 class="border-bottom pb-2 mb-3">Authentication</h6>
<div class="row mb-3">
<div class="col-md-6">
<div class="form-floating">
{{ form.auth_type }}
<label for="{{ form.auth_type.id_for_label }}">Authentication Type</label>
{% if form.auth_type.errors %}
<div class="invalid-feedback d-block">{{ form.auth_type.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-6" id="auth-details" style="display: none;">
<div class="form-floating">
{{ form.auth_credentials }}
<label for="{{ form.auth_credentials.id_for_label }}">Credentials</label>
<div class="form-text">Enter authentication credentials (will be encrypted)</div>
{% if form.auth_credentials.errors %}
<div class="invalid-feedback d-block">{{ form.auth_credentials.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
<!-- Headers -->
<h6 class="border-bottom pb-2 mb-3">Headers</h6>
<div class="mb-3">
<div id="headers-container">
<div class="row header-row mb-2">
<div class="col-md-5">
<input type="text" class="form-control" placeholder="Header name" name="header_names[]">
</div>
<div class="col-md-5">
<input type="text" class="form-control" placeholder="Header value" name="header_values[]">
</div>
<div class="col-md-2">
<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeHeader(this)">
<i class="fa fa-trash"></i>
</button>
</div>
</div>
</div>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="addHeader()">
<i class="fa fa-plus me-2"></i>Add Header
</button>
</div>
<!-- Parameters -->
<h6 class="border-bottom pb-2 mb-3">Parameters</h6>
<div class="mb-3">
<div id="parameters-container">
<div class="row parameter-row mb-2">
<div class="col-md-3">
<input type="text" class="form-control" placeholder="Parameter name" name="param_names[]">
</div>
<div class="col-md-2">
<select class="form-select" name="param_types[]">
<option value="string">String</option>
<option value="integer">Integer</option>
<option value="boolean">Boolean</option>
<option value="date">Date</option>
</select>
</div>
<div class="col-md-2">
<div class="form-check mt-2">
<input class="form-check-input" type="checkbox" name="param_required[]">
<label class="form-check-label">Required</label>
</div>
</div>
<div class="col-md-3">
<input type="text" class="form-control" placeholder="Default value" name="param_defaults[]">
</div>
<div class="col-md-2">
<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeParameter(this)">
<i class="fa fa-trash"></i>
</button>
</div>
</div>
</div>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="addParameter()">
<i class="fa fa-plus me-2"></i>Add Parameter
</button>
</div>
<!-- Response Configuration -->
<h6 class="border-bottom pb-2 mb-3">Response Configuration</h6>
<div class="row mb-3">
<div class="col-md-4">
<div class="form-floating">
{{ form.expected_status_code }}
<label for="{{ form.expected_status_code.id_for_label }}">Expected Status Code</label>
{% if form.expected_status_code.errors %}
<div class="invalid-feedback d-block">{{ form.expected_status_code.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating">
{{ form.response_format }}
<label for="{{ form.response_format.id_for_label }}">Response Format</label>
{% if form.response_format.errors %}
<div class="invalid-feedback d-block">{{ form.response_format.errors.0 }}</div>
{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating">
{{ form.status }}
<label for="{{ form.status.id_for_label }}">Status</label>
{% if form.status.errors %}
<div class="invalid-feedback d-block">{{ form.status.errors.0 }}</div>
{% endif %}
</div>
</div>
</div>
<!-- Options -->
<h6 class="border-bottom pb-2 mb-3">Options</h6>
<div class="row mb-4">
<div class="col-md-4">
<div class="form-check">
{{ form.validate_response }}
<label class="form-check-label" for="{{ form.validate_response.id_for_label }}">
Validate Response
</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check">
{{ form.log_requests }}
<label class="form-check-label" for="{{ form.log_requests.id_for_label }}">
Log Requests
</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check">
{{ form.enable_monitoring }}
<label class="form-check-label" for="{{ form.enable_monitoring.id_for_label }}">
Enable Monitoring
</label>
</div>
</div>
</div>
<!-- Action Buttons -->
<div class="d-flex justify-content-between">
<div>
<a href="{% url 'integration:api_endpoint_list' %}" class="btn btn-secondary">
<i class="fa fa-arrow-left me-2"></i>Cancel
</a>
</div>
<div>
<button type="button" class="btn btn-info me-2" onclick="testConnection()">
<i class="fa fa-play me-2"></i>Test Connection
</button>
<button type="submit" class="btn btn-primary">
<i class="fa fa-save me-2"></i>{% if object %}Update{% else %}Create{% endif %} Endpoint
</button>
</div>
</div>
</form>
</div>
</div>
<!-- END panel -->
</div>
<div class="col-xl-4">
<!-- BEGIN panel -->
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">Help & Tips</h4>
</div>
<div class="panel-body">
<div class="alert alert-info">
<h6 class="alert-heading">Configuration Tips</h6>
<ul class="mb-0 small">
<li>Use descriptive names for easy identification</li>
<li>Test the endpoint before saving</li>
<li>Set appropriate timeout values</li>
<li>Enable logging for debugging</li>
<li>Use authentication when required</li>
</ul>
</div>
<div class="card border-secondary mb-3">
<div class="card-header">
<h6 class="card-title mb-0">URL Variables</h6>
</div>
<div class="card-body">
<p class="card-text small">You can use these variables in your URL:</p>
<ul class="small mb-0">
<li><code>{base_url}</code> - System base URL</li>
<li><code>{api_version}</code> - API version</li>
<li><code>{tenant_id}</code> - Current tenant ID</li>
<li><code>{user_id}</code> - Current user ID</li>
</ul>
</div>
</div>
<div class="card border-warning">
<div class="card-header">
<h6 class="card-title mb-0">Security Notes</h6>
</div>
<div class="card-body">
<p class="card-text small">Important security considerations:</p>
<ul class="small mb-0">
<li>Credentials are encrypted at rest</li>
<li>Use HTTPS for sensitive data</li>
<li>Validate all responses</li>
<li>Monitor for unusual activity</li>
</ul>
</div>
</div>
</div>
</div>
<!-- END panel -->
{% if object %}
<!-- BEGIN panel -->
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">Current Status</h4>
</div>
<div class="panel-body">
<table class="table table-borderless table-sm">
<tr>
<td class="fw-bold" width="100">Status:</td>
<td>
<span class="badge bg-{% if object.status == 'ACTIVE' %}success{% elif object.status == 'INACTIVE' %}secondary{% else %}warning{% endif %}">
{{ object.get_status_display }}
</span>
</td>
</tr>
<tr>
<td class="fw-bold">Health:</td>
<td>
{% if object.health_status %}
<span class="badge bg-{% if object.health_status == 'HEALTHY' %}success{% elif object.health_status == 'WARNING' %}warning{% else %}danger{% endif %}">
{{ object.health_status }}
</span>
{% else %}
<span class="text-muted">Not tested</span>
{% endif %}
</td>
</tr>
<tr>
<td class="fw-bold">Last Test:</td>
<td>{{ object.last_tested|date:"M d, H:i"|default:"Never" }}</td>
</tr>
<tr>
<td class="fw-bold">Success Rate:</td>
<td>{{ object.success_rate|floatformat:1 }}%</td>
</tr>
</table>
</div>
</div>
<!-- END panel -->
{% endif %}
</div>
</div>
{% endblock %}
{% block js %}
<script>
$(document).ready(function() {
// Show/hide auth details based on auth type
$('#id_auth_type').on('change', function() {
if ($(this).val() && $(this).val() !== 'NONE') {
$('#auth-details').show();
} else {
$('#auth-details').hide();
}
}).trigger('change');
// Auto-save draft functionality
setInterval(function() {
saveDraft(true); // Silent save
}, 30000); // Every 30 seconds
});
function addHeader() {
var headerRow = `
<div class="row header-row mb-2">
<div class="col-md-5">
<input type="text" class="form-control" placeholder="Header name" name="header_names[]">
</div>
<div class="col-md-5">
<input type="text" class="form-control" placeholder="Header value" name="header_values[]">
</div>
<div class="col-md-2">
<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeHeader(this)">
<i class="fa fa-trash"></i>
</button>
</div>
</div>
`;
$('#headers-container').append(headerRow);
}
function removeHeader(button) {
$(button).closest('.header-row').remove();
}
function addParameter() {
var paramRow = `
<div class="row parameter-row mb-2">
<div class="col-md-3">
<input type="text" class="form-control" placeholder="Parameter name" name="param_names[]">
</div>
<div class="col-md-2">
<select class="form-select" name="param_types[]">
<option value="string">String</option>
<option value="integer">Integer</option>
<option value="boolean">Boolean</option>
<option value="date">Date</option>
</select>
</div>
<div class="col-md-2">
<div class="form-check mt-2">
<input class="form-check-input" type="checkbox" name="param_required[]">
<label class="form-check-label">Required</label>
</div>
</div>
<div class="col-md-3">
<input type="text" class="form-control" placeholder="Default value" name="param_defaults[]">
</div>
<div class="col-md-2">
<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeParameter(this)">
<i class="fa fa-trash"></i>
</button>
</div>
</div>
`;
$('#parameters-container').append(paramRow);
}
function removeParameter(button) {
$(button).closest('.parameter-row').remove();
}
function testConnection() {
var formData = new FormData($('#endpoint-form')[0]);
$.ajax({
url: '{% url "integration:api_endpoint_test_config" %}',
method: 'POST',
data: formData,
processData: false,
contentType: false,
beforeSend: function() {
toastr.info('Testing connection...');
},
success: function(response) {
if (response.success) {
toastr.success('Connection test successful');
} else {
toastr.error('Connection test failed: ' + response.error);
}
},
error: function() {
toastr.error('Failed to test connection');
}
});
}
function saveDraft(silent = false) {
var formData = new FormData($('#endpoint-form')[0]);
formData.append('save_draft', 'true');
$.ajax({
url: window.location.href,
method: 'POST',
data: formData,
processData: false,
contentType: false,
beforeSend: function() {
if (!silent) {
toastr.info('Saving draft...');
}
},
success: function(response) {
if (!silent) {
toastr.success('Draft saved successfully');
}
},
error: function() {
if (!silent) {
toastr.error('Failed to save draft');
}
}
});
}
</script>
{% endblock %}