458 lines
19 KiB
HTML
458 lines
19 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
|
|
{% block title %}Analytics Dashboard{% endblock %}
|
|
|
|
{% block css %}
|
|
<style>
|
|
.stat-card {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: white;
|
|
border-radius: 15px;
|
|
padding: 20px;
|
|
margin-bottom: 20px;
|
|
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
|
|
}
|
|
.stat-card.success {
|
|
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
|
}
|
|
.stat-card.warning {
|
|
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
|
}
|
|
.stat-card.danger {
|
|
background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
|
|
}
|
|
.stat-card.info {
|
|
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
|
|
}
|
|
.stat-number {
|
|
font-size: 2.5rem;
|
|
font-weight: bold;
|
|
margin-bottom: 5px;
|
|
}
|
|
.stat-label {
|
|
font-size: 0.9rem;
|
|
opacity: 0.9;
|
|
}
|
|
.activity-card {
|
|
height: 400px;
|
|
overflow-y: auto;
|
|
}
|
|
.dashboard-card {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 10px;
|
|
margin-bottom: 10px;
|
|
border-radius: 8px;
|
|
background-color: #f8f9fa;
|
|
border-left: 4px solid #007bff;
|
|
}
|
|
.dashboard-icon {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
background-color: #007bff;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: white;
|
|
font-weight: bold;
|
|
margin-right: 10px;
|
|
}
|
|
.execution-status {
|
|
padding: 2px 8px;
|
|
border-radius: 12px;
|
|
font-size: 0.8rem;
|
|
font-weight: bold;
|
|
}
|
|
.execution-status.success {
|
|
background-color: #d4edda;
|
|
color: #155724;
|
|
}
|
|
.execution-status.failed {
|
|
background-color: #f8d7da;
|
|
color: #721c24;
|
|
}
|
|
.execution-status.running {
|
|
background-color: #fff3cd;
|
|
color: #856404;
|
|
}
|
|
.data-source-health {
|
|
padding: 4px 8px;
|
|
border-radius: 12px;
|
|
font-size: 0.8rem;
|
|
font-weight: bold;
|
|
}
|
|
.data-source-health.healthy {
|
|
background-color: #d4edda;
|
|
color: #155724;
|
|
}
|
|
.data-source-health.unhealthy {
|
|
background-color: #f8d7da;
|
|
color: #721c24;
|
|
}
|
|
.metric-card {
|
|
background: white;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
margin-bottom: 15px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
border-left: 4px solid #28a745;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h1 class="h3 mb-0">Analytics Dashboard</h1>
|
|
<div class="btn-group" role="group">
|
|
<a href="{% url 'analytics:dashboard_create' %}" class="btn btn-success">
|
|
<i class="fas fa-plus"></i> New Dashboard
|
|
</a>
|
|
<a href="{% url 'analytics:report_create' %}" class="btn btn-primary">
|
|
<i class="fas fa-file-alt"></i> New Report
|
|
</a>
|
|
<a href="{% url 'analytics:data_source_create' %}" class="btn btn-info">
|
|
<i class="fas fa-database"></i> Add Data Source
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Key Performance Indicators -->
|
|
<div class="row" hx-get="{% url 'analytics:analytics_stats' %}" hx-trigger="load, every 30s">
|
|
<div class="col-md-3">
|
|
<div class="stat-card">
|
|
<div class="stat-number">{{ total_dashboards }}</div>
|
|
<div class="stat-label">Total Dashboards</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-card success">
|
|
<div class="stat-number">{{ total_reports }}</div>
|
|
<div class="stat-label">Total Reports</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-card info">
|
|
<div class="stat-number">{{ total_data_sources }}</div>
|
|
<div class="stat-label">Active Data Sources</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-card warning">
|
|
<div class="stat-number">{{ total_metrics }}</div>
|
|
<div class="stat-label">Metric Definitions</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Execution Statistics -->
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="stat-card success">
|
|
<div class="stat-number">{{ executions_today }}</div>
|
|
<div class="stat-label">Executions Today</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-card info">
|
|
<div class="stat-number">{{ successful_executions }}</div>
|
|
<div class="stat-label">Successful Today</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-card danger">
|
|
<div class="stat-number">{{ failed_executions }}</div>
|
|
<div class="stat-label">Failed Today</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-card">
|
|
<div class="stat-number">{{ healthy_data_sources }}</div>
|
|
<div class="stat-label">Healthy Sources</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Activity and Dashboard Information -->
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="card activity-card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-0">Recent Dashboards</h5>
|
|
<a href="{% url 'analytics:dashboard_list' %}" class="btn btn-sm btn-outline-primary">View All</a>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if recent_dashboards %}
|
|
{% for dashboard in recent_dashboards %}
|
|
<div class="dashboard-card">
|
|
<div class="dashboard-icon">
|
|
<i class="fas fa-chart-bar"></i>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<strong>
|
|
<a href="{% url 'analytics:dashboard_detail' dashboard.pk %}">
|
|
{{ dashboard.dashboard_name }}
|
|
</a>
|
|
</strong>
|
|
<br>
|
|
<small class="text-muted">{{ dashboard.get_category_display }} - {{ dashboard.get_visibility_display }}</small>
|
|
</div>
|
|
<div class="text-right">
|
|
<div class="text-success font-weight-bold">{{ dashboard.created_at|date:"M d" }}</div>
|
|
<small class="text-muted">Created</small>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
<p class="text-muted">No recent dashboards.</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="card activity-card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-0">Recent Reports</h5>
|
|
<a href="{% url 'analytics:report_list' %}" class="btn btn-sm btn-outline-primary">View All</a>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if recent_reports %}
|
|
{% for report in recent_reports %}
|
|
<div class="dashboard-card">
|
|
<div class="dashboard-icon">
|
|
<i class="fas fa-file-alt"></i>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<strong>
|
|
<a href="{% url 'analytics:report_detail' report.pk %}">
|
|
{{ report.report_name }}
|
|
</a>
|
|
</strong>
|
|
<br>
|
|
<small class="text-muted">{{ report.get_category_display }} - {{ report.data_source.source_name }}</small>
|
|
</div>
|
|
<div class="text-right">
|
|
<div class="text-success font-weight-bold">{{ report.created_at|date:"M d" }}</div>
|
|
<small class="text-muted">Created</small>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
<p class="text-muted">No recent reports.</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Executions and Data Source Health -->
|
|
<div class="row mt-4">
|
|
<div class="col-md-6">
|
|
<div class="card activity-card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-0">Recent Executions</h5>
|
|
<a href="{% url 'analytics:report_execution_list' %}" class="btn btn-sm btn-outline-primary">View All</a>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if recent_executions %}
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Report</th>
|
|
<th>Status</th>
|
|
<th>Duration</th>
|
|
<th>Time</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for execution in recent_executions %}
|
|
<tr>
|
|
<td>
|
|
<a href="{% url 'analytics:report_execution_detail' execution.pk %}">
|
|
{{ execution.report.report_name|truncatechars:20 }}
|
|
</a>
|
|
</td>
|
|
<td>
|
|
<span class="execution-status {% if execution.status == 'SUCCESS' %}success{% elif execution.status == 'FAILED' %}failed{% else %}running{% endif %}">
|
|
{{ execution.get_status_display }}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
{% if execution.completion_time %}
|
|
{{ execution.completion_time|timesince:execution.execution_time }}
|
|
{% else %}
|
|
-
|
|
{% endif %}
|
|
</td>
|
|
<td>{{ execution.execution_time|date:"H:i" }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<p class="text-muted">No recent executions.</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="card activity-card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-0">Data Source Health</h5>
|
|
<a href="{% url 'analytics:data_source_list' %}" class="btn btn-sm btn-outline-primary">View All</a>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="metric-card">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<h4 class="text-success mb-0">{{ healthy_data_sources }}</h4>
|
|
<small class="text-muted">Healthy Sources</small>
|
|
</div>
|
|
<i class="fas fa-check-circle fa-2x text-success"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="metric-card" style="border-left-color: #dc3545;">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<h4 class="text-danger mb-0">{{ unhealthy_data_sources }}</h4>
|
|
<small class="text-muted">Unhealthy Sources</small>
|
|
</div>
|
|
<i class="fas fa-exclamation-circle fa-2x text-danger"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick health check actions -->
|
|
<div class="mt-3">
|
|
<button class="btn btn-sm btn-outline-success" onclick="testAllDataSources()">
|
|
<i class="fas fa-heartbeat"></i> Test All Sources
|
|
</button>
|
|
<button class="btn btn-sm btn-outline-info" onclick="refreshHealthStatus()">
|
|
<i class="fas fa-sync"></i> Refresh Status
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick Actions -->
|
|
<div class="row mt-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Quick Actions</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-2">
|
|
<a href="{% url 'analytics:dashboard_list' %}" class="btn btn-outline-primary btn-block">
|
|
<i class="fas fa-chart-bar"></i><br>
|
|
All Dashboards
|
|
</a>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<a href="{% url 'analytics:report_list' %}" class="btn btn-outline-success btn-block">
|
|
<i class="fas fa-file-alt"></i><br>
|
|
All Reports
|
|
</a>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<a href="{% url 'analytics:data_source_list' %}" class="btn btn-outline-info btn-block">
|
|
<i class="fas fa-database"></i><br>
|
|
Data Sources
|
|
</a>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<a href="{% url 'analytics:metric_definition_list' %}" class="btn btn-outline-warning btn-block">
|
|
<i class="fas fa-tachometer-alt"></i><br>
|
|
Metrics
|
|
</a>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<a href="{% url 'analytics:report_execution_list' %}" class="btn btn-outline-secondary btn-block">
|
|
<i class="fas fa-play"></i><br>
|
|
Executions
|
|
</a>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<a href="{% url 'analytics:dashboard_widget_list' %}" class="btn btn-outline-dark btn-block">
|
|
<i class="fas fa-th"></i><br>
|
|
Widgets
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Performance Summary -->
|
|
<div class="row mt-4">
|
|
<div class="col-md-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">System Performance Summary</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h3 class="text-primary">{{ total_dashboards }}</h3>
|
|
<p class="text-muted">Active Dashboards</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h3 class="text-success">{{ total_reports }}</h3>
|
|
<p class="text-muted">Available Reports</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h3 class="text-info">{{ executions_today }}</h3>
|
|
<p class="text-muted">Executions Today</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h3 class="text-warning">{{ total_metrics }}</h3>
|
|
<p class="text-muted">Tracked Metrics</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function testAllDataSources() {
|
|
// Implement AJAX call to test all data sources
|
|
alert('Testing all data sources...');
|
|
}
|
|
|
|
function refreshHealthStatus() {
|
|
// Implement AJAX call to refresh health status
|
|
location.reload();
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
|