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

558 lines
24 KiB
HTML

{% extends 'base.html' %}
{% load static %}
{% block title %}{{ data_source.name }} - Data Source Details{% 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>{{ data_source.name }}</h4>
<h6>Data source details and configuration</h6>
</div>
<div class="page-btn">
<a href="{% url 'analytics:data_source_list' %}" class="btn btn-secondary me-2">
<i class="fas fa-arrow-left me-1"></i>Back to Sources
</a>
<a href="{% url 'analytics:data_source_update' data_source.pk %}" class="btn btn-primary">
<i class="fas fa-edit me-1"></i>Edit Source
</a>
</div>
</div>
</div>
</div>
<div class="row">
<!-- Main Content -->
<div class="col-lg-8">
<!-- Connection Status -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-plug me-2"></i>Connection Status
</h5>
<div class="card-tools">
<button type="button" class="btn btn-outline-primary btn-sm" onclick="testConnection()">
<i class="fas fa-plug me-1"></i>Test Connection
</button>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-3">
<div class="status-card text-center">
{% if data_source.status == 'active' %}
<i class="fas fa-check-circle fa-3x text-success mb-2"></i>
<h6 class="text-success">Connected</h6>
{% elif data_source.status == 'error' %}
<i class="fas fa-exclamation-triangle fa-3x text-danger mb-2"></i>
<h6 class="text-danger">Connection Error</h6>
{% elif data_source.status == 'syncing' %}
<i class="fas fa-sync-alt fa-3x text-info fa-spin mb-2"></i>
<h6 class="text-info">Syncing</h6>
{% else %}
<i class="fas fa-times-circle fa-3x text-secondary mb-2"></i>
<h6 class="text-secondary">Disconnected</h6>
{% endif %}
</div>
</div>
<div class="col-md-9">
<div class="connection-details">
<div class="row">
<div class="col-sm-6">
<div class="detail-item">
<label class="form-label">Last Connection Test:</label>
<span class="text-muted">{{ data_source.last_test|default:"Never tested" }}</span>
</div>
</div>
<div class="col-sm-6">
<div class="detail-item">
<label class="form-label">Response Time:</label>
<span class="text-muted">{{ data_source.response_time|default:"N/A" }}</span>
</div>
</div>
<div class="col-sm-6">
<div class="detail-item">
<label class="form-label">Last Sync:</label>
<span class="text-muted">
{% if data_source.last_sync %}
{{ data_source.last_sync|timesince }} ago
{% else %}
Never synced
{% endif %}
</span>
</div>
</div>
<div class="col-sm-6">
<div class="detail-item">
<label class="form-label">Records Count:</label>
<span class="text-muted">{{ data_source.record_count|default:"0"|floatformat:0 }}</span>
</div>
</div>
</div>
{% if data_source.last_error %}
<div class="alert alert-danger mt-3">
<h6 class="alert-heading">
<i class="fas fa-exclamation-triangle me-2"></i>Last Error
</h6>
<p class="mb-0">{{ data_source.last_error }}</p>
<small class="text-muted">{{ data_source.error_timestamp|timesince }} ago</small>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<!-- Data Preview -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-table me-2"></i>Data Preview
</h5>
<div class="card-tools">
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="refreshPreview()">
<i class="fas fa-sync-alt me-1"></i>Refresh
</button>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="exportData()">
<i class="fas fa-download me-1"></i>Export
</button>
</div>
</div>
<div class="card-body">
{% if data_source.sample_data %}
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
{% for column in data_source.columns %}
<th>{{ column.name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in data_source.sample_data %}
<tr>
{% for value in row %}
<td>{{ value|truncatechars:50 }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-4">
<i class="fas fa-table fa-3x text-muted mb-3"></i>
<h6 class="text-muted">No Data Available</h6>
<p class="text-muted">Connect and sync the data source to see preview.</p>
<button type="button" class="btn btn-primary" onclick="syncData()">
<i class="fas fa-sync-alt me-1"></i>Sync Data
</button>
</div>
{% endif %}
</div>
</div>
<!-- Sync History -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-history me-2"></i>Sync History
</h5>
</div>
<div class="card-body">
{% if data_source.sync_history %}
<div class="timeline">
{% for sync in data_source.sync_history %}
<div class="timeline-item">
<div class="timeline-marker">
{% if sync.status == 'success' %}
<i class="fas fa-check-circle text-success"></i>
{% elif sync.status == 'error' %}
<i class="fas fa-exclamation-triangle text-danger"></i>
{% else %}
<i class="fas fa-clock text-warning"></i>
{% endif %}
</div>
<div class="timeline-content">
<div class="d-flex justify-content-between align-items-start">
<div>
<h6 class="mb-1">{{ sync.get_status_display }}</h6>
<p class="text-muted mb-1">{{ sync.message }}</p>
<small class="text-muted">{{ sync.timestamp|timesince }} ago</small>
</div>
<div class="text-end">
<span class="badge bg-secondary">{{ sync.records_processed }} records</span>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-4">
<i class="fas fa-history fa-3x text-muted mb-3"></i>
<h6 class="text-muted">No Sync History</h6>
<p class="text-muted">Sync history will appear here after the first synchronization.</p>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Sidebar -->
<div class="col-lg-4">
<!-- 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="source-info">
<div class="info-item">
<label class="form-label">Name:</label>
<span class="info-value">{{ data_source.name }}</span>
</div>
<div class="info-item">
<label class="form-label">Type:</label>
<span class="badge bg-primary">{{ data_source.get_source_type_display }}</span>
</div>
<div class="info-item">
<label class="form-label">Description:</label>
<span class="info-value">{{ data_source.description|default:"No description provided" }}</span>
</div>
<div class="info-item">
<label class="form-label">Created By:</label>
<span class="info-value">{{ data_source.created_by|default:"System" }}</span>
</div>
<div class="info-item">
<label class="form-label">Created Date:</label>
<span class="info-value">{{ data_source.created_at|date:"M d, Y H:i" }}</span>
</div>
<div class="info-item">
<label class="form-label">Last Updated:</label>
<span class="info-value">{{ data_source.updated_at|date:"M d, Y H:i" }}</span>
</div>
</div>
</div>
</div>
<!-- Configuration -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-cog me-2"></i>Configuration
</h5>
</div>
<div class="card-body">
<div class="config-info">
{% if data_source.source_type == 'database' %}
<div class="info-item">
<label class="form-label">Database Type:</label>
<span class="info-value">{{ data_source.db_type|default:"Not specified" }}</span>
</div>
<div class="info-item">
<label class="form-label">Host:</label>
<span class="info-value">{{ data_source.host|default:"Not specified" }}</span>
</div>
<div class="info-item">
<label class="form-label">Database:</label>
<span class="info-value">{{ data_source.database|default:"Not specified" }}</span>
</div>
{% elif data_source.source_type == 'api' %}
<div class="info-item">
<label class="form-label">API URL:</label>
<span class="info-value">{{ data_source.api_url|default:"Not specified" }}</span>
</div>
<div class="info-item">
<label class="form-label">Authentication:</label>
<span class="info-value">{{ data_source.auth_type|default:"None" }}</span>
</div>
{% elif data_source.source_type == 'file' %}
<div class="info-item">
<label class="form-label">File Path:</label>
<span class="info-value">{{ data_source.file_path|default:"Not specified" }}</span>
</div>
<div class="info-item">
<label class="form-label">File Format:</label>
<span class="info-value">{{ data_source.file_format|default:"Not specified" }}</span>
</div>
{% endif %}
<div class="info-item">
<label class="form-label">Sync Frequency:</label>
<span class="info-value">{{ data_source.get_sync_frequency_display|default:"Manual" }}</span>
</div>
<div class="info-item">
<label class="form-label">Auto Sync:</label>
<span class="badge {% if data_source.auto_sync %}bg-success{% else %}bg-secondary{% endif %}">
{% if data_source.auto_sync %}Enabled{% else %}Disabled{% endif %}
</span>
</div>
</div>
</div>
</div>
<!-- Statistics -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-chart-bar me-2"></i>Statistics
</h5>
</div>
<div class="card-body">
<div class="stats-grid">
<div class="stat-item">
<div class="stat-value">{{ data_source.total_syncs|default:"0" }}</div>
<div class="stat-label">Total Syncs</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ data_source.successful_syncs|default:"0" }}</div>
<div class="stat-label">Successful</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ data_source.failed_syncs|default:"0" }}</div>
<div class="stat-label">Failed</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ data_source.avg_sync_time|default:"0" }}s</div>
<div class="stat-label">Avg Time</div>
</div>
</div>
</div>
</div>
<!-- Actions -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-tools me-2"></i>Actions
</h5>
</div>
<div class="card-body">
<div class="d-grid gap-2">
<button type="button" class="btn btn-primary" onclick="syncData()">
<i class="fas fa-sync-alt me-1"></i>Sync Now
</button>
<button type="button" class="btn btn-outline-secondary" onclick="testConnection()">
<i class="fas fa-plug me-1"></i>Test Connection
</button>
<a href="{% url 'analytics:data_source_update' data_source.pk %}" class="btn btn-outline-primary">
<i class="fas fa-edit me-1"></i>Edit Configuration
</a>
<button type="button" class="btn btn-outline-info" onclick="exportConfig()">
<i class="fas fa-download me-1"></i>Export Config
</button>
<hr>
<a href="{% url 'analytics:data_source_delete' data_source.pk %}" class="btn btn-outline-danger">
<i class="fas fa-trash me-1"></i>Delete Source
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
function testConnection() {
const btn = event.target.closest('button');
const originalText = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Testing...';
btn.disabled = true;
setTimeout(() => {
btn.innerHTML = originalText;
btn.disabled = false;
alert('Connection test completed successfully!');
}, 2000);
}
function syncData() {
if (confirm('Start data synchronization? This may take some time.')) {
const btn = event.target.closest('button');
const originalText = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Syncing...';
btn.disabled = true;
setTimeout(() => {
btn.innerHTML = originalText;
btn.disabled = false;
alert('Data synchronization completed successfully!');
window.location.reload();
}, 3000);
}
}
function refreshPreview() {
const btn = event.target.closest('button');
const originalText = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Loading...';
btn.disabled = true;
setTimeout(() => {
btn.innerHTML = originalText;
btn.disabled = false;
window.location.reload();
}, 1500);
}
function exportData() {
alert('Exporting data preview...');
}
function exportConfig() {
alert('Exporting data source configuration...');
}
</script>
<style>
.status-card {
padding: 20px;
background: #f8f9fa;
border-radius: 8px;
height: 100%;
}
.detail-item {
margin-bottom: 15px;
}
.detail-item label {
font-weight: 600;
margin-bottom: 5px;
display: block;
color: #2c3e50;
}
.info-item {
margin-bottom: 15px;
}
.info-item label {
font-weight: 600;
margin-bottom: 5px;
display: block;
color: #2c3e50;
}
.info-value {
color: #6c757d;
}
.timeline {
position: relative;
padding-left: 30px;
}
.timeline::before {
content: '';
position: absolute;
left: 15px;
top: 0;
bottom: 0;
width: 2px;
background: #e9ecef;
}
.timeline-item {
position: relative;
margin-bottom: 25px;
}
.timeline-marker {
position: absolute;
left: -22px;
top: 0;
width: 30px;
height: 30px;
background: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid #e9ecef;
}
.timeline-content {
background: #f8f9fa;
padding: 15px;
border-radius: 8px;
border-left: 3px solid #007bff;
}
.stats-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
}
.stat-item {
text-align: center;
padding: 15px;
background: #f8f9fa;
border-radius: 8px;
}
.stat-value {
font-size: 1.5rem;
font-weight: 700;
color: #2c3e50;
margin-bottom: 5px;
}
.stat-label {
font-size: 0.875rem;
color: #6c757d;
}
@media (max-width: 768px) {
.page-btn {
margin-top: 15px;
}
.card-tools {
margin-top: 15px;
}
.timeline {
padding-left: 20px;
}
.timeline-marker {
left: -15px;
width: 25px;
height: 25px;
}
.stats-grid {
grid-template-columns: 1fr;
}
.status-card {
margin-bottom: 20px;
}
}
</style>
{% endblock %}