hospital-management/templates/analytics/data_source_form.html
2025-08-12 13:33:25 +03:00

615 lines
34 KiB
HTML

{% extends 'base.html' %}
{% load static %}
{% block title %}{% if data_source %}Edit Data Source{% else %}Create Data Source{% endif %} - Hospital Management{% endblock %}
{% block content %}
<div class="content">
<div class="container-fluid">
<!-- Page Header -->
<div class="row">
<div class="col-12">
<div class="page-header">
<div class="page-title">
<h4>{% if data_source %}Edit Data Source{% else %}Create New Data Source{% endif %}</h4>
<h6>{% if data_source %}Update data source configuration{% else %}Add a new data source for analytics{% endif %}</h6>
</div>
<div class="page-btn">
<a href="{% url 'analytics:data_source_list' %}" class="btn btn-secondary">
<i class="fas fa-arrow-left me-1"></i>Back to Sources
</a>
</div>
</div>
</div>
</div>
<form method="post" id="dataSourceForm">
{% csrf_token %}
<div class="row">
<!-- Main Form -->
<div class="col-lg-8">
<!-- Basic Information -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-info-circle me-2"></i>Basic Information
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name" class="form-label">Data Source Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="name" name="name"
value="{{ data_source.name|default:'' }}"
placeholder="Enter data source name" required>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="source_type" class="form-label">Source Type <span class="text-danger">*</span></label>
<select class="form-select" id="source_type" name="source_type" required onchange="updateSourceConfig()">
<option value="">Select source type</option>
<option value="database" {% if data_source.source_type == 'database' %}selected{% endif %}>Database</option>
<option value="api" {% if data_source.source_type == 'api' %}selected{% endif %}>API</option>
<option value="file" {% if data_source.source_type == 'file' %}selected{% endif %}>File</option>
<option value="stream" {% if data_source.source_type == 'stream' %}selected{% endif %}>Stream</option>
</select>
</div>
</div>
</div>
<div class="form-group">
<label for="description" class="form-label">Description</label>
<textarea class="form-control" id="description" name="description" rows="3"
placeholder="Describe the data source and its purpose">{{ data_source.description|default:'' }}</textarea>
</div>
</div>
</div>
<!-- Database Configuration -->
<div class="card" id="databaseConfig" style="display: none;">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-database me-2"></i>Database Configuration
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="db_type" class="form-label">Database Type</label>
<select class="form-select" id="db_type" name="db_type">
<option value="postgresql" {% if data_source.db_type == 'postgresql' %}selected{% endif %}>PostgreSQL</option>
<option value="mysql" {% if data_source.db_type == 'mysql' %}selected{% endif %}>MySQL</option>
<option value="sqlite" {% if data_source.db_type == 'sqlite' %}selected{% endif %}>SQLite</option>
<option value="oracle" {% if data_source.db_type == 'oracle' %}selected{% endif %}>Oracle</option>
<option value="mssql" {% if data_source.db_type == 'mssql' %}selected{% endif %}>SQL Server</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="host" class="form-label">Host</label>
<input type="text" class="form-control" id="host" name="host"
value="{{ data_source.host|default:'' }}"
placeholder="localhost">
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label for="port" class="form-label">Port</label>
<input type="number" class="form-control" id="port" name="port"
value="{{ data_source.port|default:'' }}"
placeholder="5432">
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="database" class="form-label">Database Name</label>
<input type="text" class="form-control" id="database" name="database"
value="{{ data_source.database|default:'' }}"
placeholder="database_name">
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="schema" class="form-label">Schema (Optional)</label>
<input type="text" class="form-control" id="schema" name="schema"
value="{{ data_source.schema|default:'' }}"
placeholder="public">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" name="username"
value="{{ data_source.username|default:'' }}"
placeholder="database_user">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password"
placeholder="{% if data_source %}Leave blank to keep current{% else %}Enter password{% endif %}">
</div>
</div>
</div>
</div>
</div>
<!-- API Configuration -->
<div class="card" id="apiConfig" style="display: none;">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-plug me-2"></i>API Configuration
</h5>
</div>
<div class="card-body">
<div class="form-group">
<label for="api_url" class="form-label">API URL</label>
<input type="url" class="form-control" id="api_url" name="api_url"
value="{{ data_source.api_url|default:'' }}"
placeholder="https://api.example.com/data">
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="auth_type" class="form-label">Authentication Type</label>
<select class="form-select" id="auth_type" name="auth_type" onchange="updateAuthFields()">
<option value="none" {% if data_source.auth_type == 'none' %}selected{% endif %}>None</option>
<option value="api_key" {% if data_source.auth_type == 'api_key' %}selected{% endif %}>API Key</option>
<option value="bearer" {% if data_source.auth_type == 'bearer' %}selected{% endif %}>Bearer Token</option>
<option value="basic" {% if data_source.auth_type == 'basic' %}selected{% endif %}>Basic Auth</option>
<option value="oauth" {% if data_source.auth_type == 'oauth' %}selected{% endif %}>OAuth 2.0</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="request_method" class="form-label">Request Method</label>
<select class="form-select" id="request_method" name="request_method">
<option value="GET" {% if data_source.request_method == 'GET' %}selected{% endif %}>GET</option>
<option value="POST" {% if data_source.request_method == 'POST' %}selected{% endif %}>POST</option>
<option value="PUT" {% if data_source.request_method == 'PUT' %}selected{% endif %}>PUT</option>
</select>
</div>
</div>
</div>
<div id="authFields">
<!-- Auth fields will be populated by JavaScript -->
</div>
<div class="form-group">
<label for="headers" class="form-label">Custom Headers (JSON)</label>
<textarea class="form-control" id="headers" name="headers" rows="3"
placeholder='{"Content-Type": "application/json"}'>{{ data_source.headers|default:'' }}</textarea>
</div>
</div>
</div>
<!-- File Configuration -->
<div class="card" id="fileConfig" style="display: none;">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-file me-2"></i>File Configuration
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label for="file_path" class="form-label">File Path</label>
<input type="text" class="form-control" id="file_path" name="file_path"
value="{{ data_source.file_path|default:'' }}"
placeholder="/path/to/data/file.csv">
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="file_format" class="form-label">File Format</label>
<select class="form-select" id="file_format" name="file_format">
<option value="csv" {% if data_source.file_format == 'csv' %}selected{% endif %}>CSV</option>
<option value="json" {% if data_source.file_format == 'json' %}selected{% endif %}>JSON</option>
<option value="xml" {% if data_source.file_format == 'xml' %}selected{% endif %}>XML</option>
<option value="excel" {% if data_source.file_format == 'excel' %}selected{% endif %}>Excel</option>
<option value="parquet" {% if data_source.file_format == 'parquet' %}selected{% endif %}>Parquet</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="delimiter" class="form-label">Delimiter (CSV only)</label>
<input type="text" class="form-control" id="delimiter" name="delimiter"
value="{{ data_source.delimiter|default:',' }}"
placeholder="," maxlength="1">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="encoding" class="form-label">Encoding</label>
<select class="form-select" id="encoding" name="encoding">
<option value="utf-8" {% if data_source.encoding == 'utf-8' %}selected{% endif %}>UTF-8</option>
<option value="latin-1" {% if data_source.encoding == 'latin-1' %}selected{% endif %}>Latin-1</option>
<option value="ascii" {% if data_source.encoding == 'ascii' %}selected{% endif %}>ASCII</option>
</select>
</div>
</div>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="has_header" name="has_header"
{% if data_source.has_header %}checked{% endif %}>
<label class="form-check-label" for="has_header">
File has header row
</label>
</div>
</div>
</div>
<!-- Stream Configuration -->
<div class="card" id="streamConfig" style="display: none;">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-stream me-2"></i>Stream Configuration
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="stream_type" class="form-label">Stream Type</label>
<select class="form-select" id="stream_type" name="stream_type">
<option value="kafka" {% if data_source.stream_type == 'kafka' %}selected{% endif %}>Apache Kafka</option>
<option value="rabbitmq" {% if data_source.stream_type == 'rabbitmq' %}selected{% endif %}>RabbitMQ</option>
<option value="redis" {% if data_source.stream_type == 'redis' %}selected{% endif %}>Redis Streams</option>
<option value="websocket" {% if data_source.stream_type == 'websocket' %}selected{% endif %}>WebSocket</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="stream_url" class="form-label">Stream URL</label>
<input type="text" class="form-control" id="stream_url" name="stream_url"
value="{{ data_source.stream_url|default:'' }}"
placeholder="localhost:9092">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="topic" class="form-label">Topic/Queue</label>
<input type="text" class="form-control" id="topic" name="topic"
value="{{ data_source.topic|default:'' }}"
placeholder="data-topic">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="consumer_group" class="form-label">Consumer Group</label>
<input type="text" class="form-control" id="consumer_group" name="consumer_group"
value="{{ data_source.consumer_group|default:'' }}"
placeholder="analytics-group">
</div>
</div>
</div>
</div>
</div>
<!-- Sync Settings -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-sync-alt me-2"></i>Sync Settings
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="sync_frequency" class="form-label">Sync Frequency</label>
<select class="form-select" id="sync_frequency" name="sync_frequency">
<option value="manual" {% if data_source.sync_frequency == 'manual' %}selected{% endif %}>Manual</option>
<option value="hourly" {% if data_source.sync_frequency == 'hourly' %}selected{% endif %}>Hourly</option>
<option value="daily" {% if data_source.sync_frequency == 'daily' %}selected{% endif %}>Daily</option>
<option value="weekly" {% if data_source.sync_frequency == 'weekly' %}selected{% endif %}>Weekly</option>
<option value="monthly" {% if data_source.sync_frequency == 'monthly' %}selected{% endif %}>Monthly</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="batch_size" class="form-label">Batch Size</label>
<input type="number" class="form-control" id="batch_size" name="batch_size"
value="{{ data_source.batch_size|default:'1000' }}"
placeholder="1000" min="1">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="auto_sync" name="auto_sync"
{% if data_source.auto_sync %}checked{% endif %}>
<label class="form-check-label" for="auto_sync">
Enable automatic synchronization
</label>
</div>
</div>
<div class="col-md-6">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="is_active" name="is_active"
{% if data_source.is_active or not data_source %}checked{% endif %}>
<label class="form-check-label" for="is_active">
Active data source
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Sidebar -->
<div class="col-lg-4">
<!-- Connection Test -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-plug me-2"></i>Connection Test
</h5>
</div>
<div class="card-body">
<div class="text-center">
<button type="button" class="btn btn-outline-primary" onclick="testConnection()">
<i class="fas fa-plug me-1"></i>Test Connection
</button>
<div id="connectionResult" class="mt-3" style="display: none;">
<!-- Test result will be shown here -->
</div>
</div>
</div>
</div>
<!-- Form Actions -->
<div class="card">
<div class="card-body">
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save me-1"></i>
{% if data_source %}Update Data Source{% else %}Create Data Source{% endif %}
</button>
{% if data_source %}
<button type="button" class="btn btn-outline-secondary" onclick="syncNow()">
<i class="fas fa-sync-alt me-1"></i>Sync After Save
</button>
{% endif %}
<a href="{% url 'analytics:data_source_list' %}" class="btn btn-outline-danger">
<i class="fas fa-times me-1"></i>Cancel
</a>
</div>
</div>
</div>
<!-- Help -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-question-circle me-2"></i>Help
</h5>
</div>
<div class="card-body">
<div class="help-content">
<h6>Data Source Types:</h6>
<ul class="list-unstyled">
<li><strong>Database:</strong> Connect to SQL databases</li>
<li><strong>API:</strong> Fetch data from REST APIs</li>
<li><strong>File:</strong> Import from files (CSV, JSON, etc.)</li>
<li><strong>Stream:</strong> Real-time data streams</li>
</ul>
<h6 class="mt-3">Sync Frequency:</h6>
<p class="text-muted small">
Choose how often the data should be synchronized.
Manual sync requires manual triggering.
</p>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize form based on existing data
updateSourceConfig();
updateAuthFields();
});
function updateSourceConfig() {
const sourceType = document.getElementById('source_type').value;
// Hide all config sections
document.getElementById('databaseConfig').style.display = 'none';
document.getElementById('apiConfig').style.display = 'none';
document.getElementById('fileConfig').style.display = 'none';
document.getElementById('streamConfig').style.display = 'none';
// Show relevant config section
if (sourceType === 'database') {
document.getElementById('databaseConfig').style.display = 'block';
} else if (sourceType === 'api') {
document.getElementById('apiConfig').style.display = 'block';
} else if (sourceType === 'file') {
document.getElementById('fileConfig').style.display = 'block';
} else if (sourceType === 'stream') {
document.getElementById('streamConfig').style.display = 'block';
}
}
function updateAuthFields() {
const authType = document.getElementById('auth_type').value;
const authFields = document.getElementById('authFields');
authFields.innerHTML = '';
if (authType === 'api_key') {
authFields.innerHTML = `
<div class="form-group">
<label for="api_key" class="form-label">API Key</label>
<input type="password" class="form-control" id="api_key" name="api_key"
value="{{ data_source.api_key|default:'' }}"
placeholder="Enter API key">
</div>
`;
} else if (authType === 'bearer') {
authFields.innerHTML = `
<div class="form-group">
<label for="bearer_token" class="form-label">Bearer Token</label>
<input type="password" class="form-control" id="bearer_token" name="bearer_token"
value="{{ data_source.bearer_token|default:'' }}"
placeholder="Enter bearer token">
</div>
`;
} else if (authType === 'basic') {
authFields.innerHTML = `
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="basic_username" class="form-label">Username</label>
<input type="text" class="form-control" id="basic_username" name="basic_username"
value="{{ data_source.basic_username|default:'' }}"
placeholder="Username">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="basic_password" class="form-label">Password</label>
<input type="password" class="form-control" id="basic_password" name="basic_password"
placeholder="Password">
</div>
</div>
</div>
`;
} else if (authType === 'oauth') {
authFields.innerHTML = `
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="client_id" class="form-label">Client ID</label>
<input type="text" class="form-control" id="client_id" name="client_id"
value="{{ data_source.client_id|default:'' }}"
placeholder="OAuth Client ID">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="client_secret" class="form-label">Client Secret</label>
<input type="password" class="form-control" id="client_secret" name="client_secret"
placeholder="OAuth Client Secret">
</div>
</div>
</div>
`;
}
}
function testConnection() {
const btn = event.target;
const originalText = btn.innerHTML;
const resultDiv = document.getElementById('connectionResult');
btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Testing...';
btn.disabled = true;
// Simulate connection test
setTimeout(() => {
btn.innerHTML = originalText;
btn.disabled = false;
resultDiv.innerHTML = `
<div class="alert alert-success">
<i class="fas fa-check-circle me-2"></i>
Connection successful!
</div>
`;
resultDiv.style.display = 'block';
}, 2000);
}
function syncNow() {
document.getElementById('sync_after_save').value = 'true';
}
// Form validation
document.getElementById('dataSourceForm').addEventListener('submit', function(e) {
const name = document.getElementById('name').value.trim();
const sourceType = document.getElementById('source_type').value;
if (!name || !sourceType) {
e.preventDefault();
alert('Please fill in all required fields');
return;
}
// Show loading state
const submitBtn = document.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Saving...';
submitBtn.disabled = true;
// Re-enable after delay (in real app, handled by form submission)
setTimeout(() => {
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
}, 2000);
});
</script>
<style>
.help-content h6 {
color: #2c3e50;
font-weight: 600;
margin-bottom: 10px;
}
.help-content ul li {
margin-bottom: 5px;
font-size: 0.875rem;
}
.help-content ul li strong {
color: #2c3e50;
}
@media (max-width: 768px) {
.page-btn {
margin-top: 15px;
}
.help-content {
font-size: 0.875rem;
}
}
</style>
{% endblock %}