Initial commit: Clean Mold Cost Calculator application
- Flask-based mold cost calculation application - PostgreSQL database with SQLAlchemy ORM - Docker/Podman containerization - Comprehensive documentation in docs/ - Clean, organized codebase without obsolete files - Production-ready deployment configuration - Enhanced pytest configuration with coverage reporting - Master/Development branch structure
This commit is contained in:
@@ -0,0 +1,245 @@
|
||||
{% extends "admin/base.html" %}
|
||||
|
||||
{% block title %}Admin Dashboard{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<!-- Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-0">
|
||||
<i class="bi bi-speedometer2 me-2 text-primary"></i>Admin Dashboard
|
||||
</h1>
|
||||
<p class="text-muted mb-0">Overview of system statistics and recent activity</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Flash Messages -->
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="alert alert-{{ category }} alert-dismissible fade show" role="alert">
|
||||
<i class="bi bi-info-circle me-2"></i>{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<!-- Statistics Cards -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-xl-3 col-md-6 mb-3">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Total Users</h6>
|
||||
<h3 class="mb-0">{{ total_users }}</h3>
|
||||
</div>
|
||||
<div class="bg-primary bg-opacity-10 rounded-circle p-3">
|
||||
<i class="bi bi-people text-primary fs-1"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<span class="badge bg-success">
|
||||
<i class="bi bi-check-circle me-1"></i>{{ active_users }} active
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-3 col-md-6 mb-3">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Total Quotations</h6>
|
||||
<h3 class="mb-0">{{ total_quotations }}</h3>
|
||||
</div>
|
||||
<div class="bg-success bg-opacity-10 rounded-circle p-3">
|
||||
<i class="bi bi-file-earmark-text text-success fs-1"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<span class="badge bg-info">
|
||||
<i class="bi bi-graph-up me-1"></i>All time
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-3 col-md-6 mb-3">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Active Regions</h6>
|
||||
<h3 class="mb-0">{{ active_regions }}</h3>
|
||||
</div>
|
||||
<div class="bg-warning bg-opacity-10 rounded-circle p-3">
|
||||
<i class="bi bi-globe text-warning fs-1"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<span class="badge bg-warning">
|
||||
<i class="bi bi-flag me-1"></i>Active regions
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-3 col-md-6 mb-3">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1">Recent Quotes</h6>
|
||||
<h3 class="mb-0">{{ recent_quotations|length }}</h3>
|
||||
</div>
|
||||
<div class="bg-info bg-opacity-10 rounded-circle p-3">
|
||||
<i class="bi bi-clock text-info fs-1"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<span class="badge bg-info">
|
||||
<i class="bi bi-calendar me-1"></i>Last 5 quotes
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Recent Activity -->
|
||||
<div class="col-lg-8 mb-4">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-header bg-light border-0">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="bi bi-graph-up me-2 text-primary"></i>Recent Activity
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if recent_quotations %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>User</th>
|
||||
<th>Project</th>
|
||||
<th>Amount</th>
|
||||
<th>Date</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for quotation in recent_quotations %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="avatar-sm bg-primary bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center me-3" style="width: 32px; height: 32px;">
|
||||
<i class="bi bi-person text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-medium">{{ quotation.user.username }}</div>
|
||||
<small class="text-muted">{{ quotation.user.email }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ quotation.project_name }}</td>
|
||||
<td>
|
||||
<span class="badge bg-success">${{ "%.2f"|format(quotation.total_cost) }}</span>
|
||||
</td>
|
||||
<td>{{ quotation.created_at.strftime('%Y-%m-%d %H:%M') }}</td>
|
||||
<td>
|
||||
<span class="badge bg-primary">Completed</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="text-center mt-3">
|
||||
<a href="{{ url_for('admin.quotations') }}" class="btn btn-outline-primary">
|
||||
<i class="bi bi-eye me-1"></i>View All Quotations
|
||||
</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-4">
|
||||
<i class="bi bi-file-earmark-text fs-1 text-muted mb-3"></i>
|
||||
<p class="text-muted mb-0">No recent quotations found.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="col-lg-4 mb-4">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-header bg-light border-0">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="bi bi-lightning me-2 text-warning"></i>Quick Actions
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<a href="{{ url_for('admin.users') }}" class="btn btn-outline-primary">
|
||||
<i class="bi bi-people me-2"></i>Manage Users
|
||||
</a>
|
||||
<a href="{{ url_for('admin.quotations') }}" class="btn btn-outline-success">
|
||||
<i class="bi bi-file-earmark-text me-2"></i>View Quotations
|
||||
</a>
|
||||
<a href="{{ url_for('admin.cost_factors') }}" class="btn btn-outline-warning">
|
||||
<i class="bi bi-gear me-2"></i>Cost Factors
|
||||
</a>
|
||||
<a href="{{ url_for('admin.cost_factors') }}" class="btn btn-outline-info">
|
||||
<i class="bi bi-calculator me-2"></i>Calculator Settings
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.card {
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
|
||||
.avatar-sm {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.table th {
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.table td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
.btn {
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user