458 lines
23 KiB
HTML
458 lines
23 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}{% if object %}Edit Integration Log{% else %}New Integration Log{% endif %}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div>
|
|
<ol class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'core:integration_log_list' %}">Integration Logs</a></li>
|
|
<li class="breadcrumb-item active">{% if object %}Edit{% else %}New{% endif %}</li>
|
|
</ol>
|
|
<h1 class="page-header mb-0">
|
|
{% if object %}Edit Integration Log{% else %}Create Integration Log{% endif %}
|
|
</h1>
|
|
</div>
|
|
<div class="ms-auto">
|
|
<a href="{% url 'core:integration_log_list' %}" class="btn btn-secondary">
|
|
<i class="fas fa-arrow-left me-2"></i>Back to List
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-xl-8">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">
|
|
<i class="fas fa-exchange-alt me-2"></i>
|
|
Integration Log Details
|
|
</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if messages %}
|
|
{% for message in messages %}
|
|
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
|
{{ message }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
|
|
<form method="post" novalidate>
|
|
{% csrf_token %}
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.integration_name.id_for_label }}" class="form-label">Integration Name *</label>
|
|
<input type="text"
|
|
class="form-control {% if form.integration_name.errors %}is-invalid{% endif %}"
|
|
id="{{ form.integration_name.id_for_label }}"
|
|
name="{{ form.integration_name.name }}"
|
|
value="{{ form.integration_name.value|default:'' }}"
|
|
placeholder="Enter integration name"
|
|
required>
|
|
{% if form.integration_name.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.integration_name.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.operation_type.id_for_label }}" class="form-label">Operation Type *</label>
|
|
<select class="form-select {% if form.operation_type.errors %}is-invalid{% endif %}"
|
|
id="{{ form.operation_type.id_for_label }}"
|
|
name="{{ form.operation_type.name }}"
|
|
required>
|
|
<option value="">Select Operation Type</option>
|
|
{% for choice in form.operation_type.field.choices %}
|
|
<option value="{{ choice.0 }}" {% if choice.0 == form.operation_type.value %}selected{% endif %}>
|
|
{{ choice.1 }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
{% if form.operation_type.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.operation_type.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.status.id_for_label }}" class="form-label">Status *</label>
|
|
<select class="form-select {% if form.status.errors %}is-invalid{% endif %}"
|
|
id="{{ form.status.id_for_label }}"
|
|
name="{{ form.status.name }}"
|
|
required>
|
|
{% for choice in form.status.field.choices %}
|
|
<option value="{{ choice.0 }}" {% if choice.0 == form.status.value %}selected{% endif %}>
|
|
{{ choice.1 }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
{% if form.status.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.status.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.execution_time.id_for_label }}" class="form-label">Execution Time (ms)</label>
|
|
<input type="number"
|
|
class="form-control {% if form.execution_time.errors %}is-invalid{% endif %}"
|
|
id="{{ form.execution_time.id_for_label }}"
|
|
name="{{ form.execution_time.name }}"
|
|
value="{{ form.execution_time.value|default:'' }}"
|
|
min="0"
|
|
step="1"
|
|
placeholder="Enter execution time in milliseconds">
|
|
{% if form.execution_time.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.execution_time.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.started_at.id_for_label }}" class="form-label">Started At</label>
|
|
<input type="datetime-local"
|
|
class="form-control {% if form.started_at.errors %}is-invalid{% endif %}"
|
|
id="{{ form.started_at.id_for_label }}"
|
|
name="{{ form.started_at.name }}"
|
|
value="{{ form.started_at.value|default:'' }}">
|
|
{% if form.started_at.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.started_at.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.completed_at.id_for_label }}" class="form-label">Completed At</label>
|
|
<input type="datetime-local"
|
|
class="form-control {% if form.completed_at.errors %}is-invalid{% endif %}"
|
|
id="{{ form.completed_at.id_for_label }}"
|
|
name="{{ form.completed_at.name }}"
|
|
value="{{ form.completed_at.value|default:'' }}">
|
|
{% if form.completed_at.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.completed_at.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.request_data.id_for_label }}" class="form-label">Request Data</label>
|
|
<textarea class="form-control {% if form.request_data.errors %}is-invalid{% endif %}"
|
|
id="{{ form.request_data.id_for_label }}"
|
|
name="{{ form.request_data.name }}"
|
|
rows="5"
|
|
placeholder="Enter request data (JSON format recommended)">{{ form.request_data.value|default:'' }}</textarea>
|
|
{% if form.request_data.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.request_data.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">
|
|
Enter the request payload or parameters sent to the integration endpoint.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.response_data.id_for_label }}" class="form-label">Response Data</label>
|
|
<textarea class="form-control {% if form.response_data.errors %}is-invalid{% endif %}"
|
|
id="{{ form.response_data.id_for_label }}"
|
|
name="{{ form.response_data.name }}"
|
|
rows="5"
|
|
placeholder="Enter response data (JSON format recommended)">{{ form.response_data.value|default:'' }}</textarea>
|
|
{% if form.response_data.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.response_data.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">
|
|
Enter the response received from the integration endpoint.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.error_message.id_for_label }}" class="form-label">Error Message</label>
|
|
<textarea class="form-control {% if form.error_message.errors %}is-invalid{% endif %}"
|
|
id="{{ form.error_message.id_for_label }}"
|
|
name="{{ form.error_message.name }}"
|
|
rows="3"
|
|
placeholder="Enter any error messages or issues encountered">{{ form.error_message.value|default:'' }}</textarea>
|
|
{% if form.error_message.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.error_message.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.retry_count.id_for_label }}" class="form-label">Retry Count</label>
|
|
<input type="number"
|
|
class="form-control {% if form.retry_count.errors %}is-invalid{% endif %}"
|
|
id="{{ form.retry_count.id_for_label }}"
|
|
name="{{ form.retry_count.name }}"
|
|
value="{{ form.retry_count.value|default:'0' }}"
|
|
min="0"
|
|
max="10">
|
|
{% if form.retry_count.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.retry_count.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.external_id.id_for_label }}" class="form-label">External ID</label>
|
|
<input type="text"
|
|
class="form-control {% if form.external_id.errors %}is-invalid{% endif %}"
|
|
id="{{ form.external_id.id_for_label }}"
|
|
name="{{ form.external_id.name }}"
|
|
value="{{ form.external_id.value|default:'' }}"
|
|
placeholder="External system identifier">
|
|
{% if form.external_id.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.external_id.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.metadata.id_for_label }}" class="form-label">Metadata</label>
|
|
<textarea class="form-control {% if form.metadata.errors %}is-invalid{% endif %}"
|
|
id="{{ form.metadata.id_for_label }}"
|
|
name="{{ form.metadata.name }}"
|
|
rows="3"
|
|
placeholder="Additional metadata (JSON format recommended)">{{ form.metadata.value|default:'' }}</textarea>
|
|
{% if form.metadata.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.metadata.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">
|
|
Additional information about the integration operation.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-between">
|
|
<div>
|
|
{% if object %}
|
|
<a href="{% url 'core:integration_log_detail' object.pk %}" class="btn btn-secondary">
|
|
<i class="fas fa-times me-2"></i>Cancel
|
|
</a>
|
|
{% else %}
|
|
<a href="{% url 'core:integration_log_list' %}" class="btn btn-secondary">
|
|
<i class="fas fa-times me-2"></i>Cancel
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
<div>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-save me-2"></i>
|
|
{% if object %}Update Log{% else %}Create Log{% endif %}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-4">
|
|
<!-- Status Guide -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
Status Guide
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<span class="badge bg-warning me-2">Pending</span>
|
|
<small>Operation queued for execution</small>
|
|
</div>
|
|
<div class="mb-3">
|
|
<span class="badge bg-info me-2">Running</span>
|
|
<small>Currently executing</small>
|
|
</div>
|
|
<div class="mb-3">
|
|
<span class="badge bg-success me-2">Success</span>
|
|
<small>Completed successfully</small>
|
|
</div>
|
|
<div class="mb-3">
|
|
<span class="badge bg-danger me-2">Failed</span>
|
|
<small>Execution failed</small>
|
|
</div>
|
|
<div>
|
|
<span class="badge bg-secondary me-2">Cancelled</span>
|
|
<small>Operation cancelled</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Operation Types -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title">
|
|
<i class="fas fa-cogs me-2"></i>
|
|
Operation Types
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<i class="fas fa-download text-primary me-2"></i>
|
|
<strong>Import</strong>
|
|
<div class="small text-muted">Data import from external system</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<i class="fas fa-upload text-success me-2"></i>
|
|
<strong>Export</strong>
|
|
<div class="small text-muted">Data export to external system</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<i class="fas fa-sync text-warning me-2"></i>
|
|
<strong>Sync</strong>
|
|
<div class="small text-muted">Bidirectional synchronization</div>
|
|
</div>
|
|
<div>
|
|
<i class="fas fa-paper-plane text-info me-2"></i>
|
|
<strong>API Call</strong>
|
|
<div class="small text-muted">External API request</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick Actions -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">
|
|
<i class="fas fa-bolt me-2"></i>
|
|
Quick Actions
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-grid gap-2">
|
|
<button type="button" class="btn btn-outline-primary btn-sm" onclick="setCurrentTime('started_at')">
|
|
<i class="fas fa-play me-2"></i>Set Start Time
|
|
</button>
|
|
<button type="button" class="btn btn-outline-success btn-sm" onclick="setCurrentTime('completed_at')">
|
|
<i class="fas fa-check me-2"></i>Set Completion Time
|
|
</button>
|
|
<button type="button" class="btn btn-outline-info btn-sm" onclick="formatJSON('request_data')">
|
|
<i class="fas fa-code me-2"></i>Format Request JSON
|
|
</button>
|
|
<button type="button" class="btn btn-outline-info btn-sm" onclick="formatJSON('response_data')">
|
|
<i class="fas fa-code me-2"></i>Format Response JSON
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const statusSelect = document.getElementById('{{ form.status.id_for_label }}');
|
|
const errorMessageField = document.getElementById('{{ form.error_message.id_for_label }}');
|
|
const startedAtField = document.getElementById('{{ form.started_at.id_for_label }}');
|
|
const completedAtField = document.getElementById('{{ form.completed_at.id_for_label }}');
|
|
|
|
// Show/hide fields based on status
|
|
function toggleFieldsBasedOnStatus() {
|
|
const status = statusSelect.value;
|
|
|
|
if (status === 'failed') {
|
|
errorMessageField.parentElement.style.display = 'block';
|
|
} else if (status === 'success') {
|
|
errorMessageField.parentElement.style.display = 'none';
|
|
errorMessageField.value = '';
|
|
}
|
|
|
|
// Auto-set timestamps based on status
|
|
if (status === 'running' && !startedAtField.value) {
|
|
setCurrentTime('started_at');
|
|
} else if ((status === 'success' || status === 'failed') && !completedAtField.value) {
|
|
setCurrentTime('completed_at');
|
|
}
|
|
}
|
|
|
|
statusSelect.addEventListener('change', toggleFieldsBasedOnStatus);
|
|
toggleFieldsBasedOnStatus(); // Initial call
|
|
|
|
// Calculate execution time automatically
|
|
function calculateExecutionTime() {
|
|
const startTime = new Date(startedAtField.value);
|
|
const endTime = new Date(completedAtField.value);
|
|
|
|
if (startTime && endTime && endTime > startTime) {
|
|
const executionTime = endTime - startTime;
|
|
document.getElementById('{{ form.execution_time.id_for_label }}').value = executionTime;
|
|
}
|
|
}
|
|
|
|
startedAtField.addEventListener('change', calculateExecutionTime);
|
|
completedAtField.addEventListener('change', calculateExecutionTime);
|
|
});
|
|
|
|
function setCurrentTime(fieldSuffix) {
|
|
const now = new Date();
|
|
const isoString = now.toISOString().slice(0, 16); // Format for datetime-local
|
|
const field = document.getElementById(`{{ form.${fieldSuffix}.id_for_label }}`.replace('${fieldSuffix}', fieldSuffix));
|
|
if (field) {
|
|
field.value = isoString;
|
|
|
|
// Trigger calculation if both times are set
|
|
if (fieldSuffix === 'completed_at') {
|
|
const startField = document.getElementById('{{ form.started_at.id_for_label }}');
|
|
if (startField.value) {
|
|
const startTime = new Date(startField.value);
|
|
const endTime = new Date(isoString);
|
|
const executionTime = endTime - startTime;
|
|
document.getElementById('{{ form.execution_time.id_for_label }}').value = executionTime;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function formatJSON(fieldName) {
|
|
const field = document.getElementById(`{{ form.${fieldName}.id_for_label }}`.replace('${fieldName}', fieldName));
|
|
if (field && field.value.trim()) {
|
|
try {
|
|
const parsed = JSON.parse(field.value);
|
|
field.value = JSON.stringify(parsed, null, 2);
|
|
} catch (e) {
|
|
alert('Invalid JSON format. Please check the syntax.');
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
|