Files
TimeTracker/templates/admin/dashboard.html
Dries Peeters 8a378b7078 feat(clients,license,db): add client management, enhanced DB init, and tests
- Clients: add model, routes, and templates
  - app/models/client.py
  - app/routes/clients.py
  - templates/clients/{create,edit,list,view}.html
  - docs/CLIENT_MANAGEMENT_README.md
- Database: add enhanced init/verify scripts, migrations, and docs
  - docker/{init-database-enhanced.py,start-enhanced.py,verify-database.py}
  - docs/ENHANCED_DATABASE_STARTUP.md
  - migrations/{add_analytics_column.sql,add_analytics_setting.py,migrate_to_client_model.py}
- Scripts: add version manager and docker network test helpers
  - scripts/version-manager.{bat,ps1,py,sh}
  - scripts/test-docker-network.{bat,sh}
  - docs/VERSION_MANAGEMENT.md
- UI: tweak base stylesheet
  - app/static/base.css
- Tests: add client system test
  - test_client_system.py
2025-09-01 11:34:45 +02:00

256 lines
11 KiB
HTML

{% extends "base.html" %}
{% block title %}Admin Dashboard - {{ app_name }}{% 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">
<i class="fas fa-cogs text-primary"></i> Admin Dashboard
</h1>
<div>
<a href="{{ url_for('admin.system_info') }}" class="btn btn-outline-info">
<i class="fas fa-info-circle"></i> System Info
</a>
<a href="{{ url_for('admin.backup') }}" class="btn btn-outline-warning">
<i class="fas fa-download"></i> Backup
</a>
<a href="{{ url_for('admin.license_status') }}" class="btn btn-outline-info">
<i class="fas fa-key"></i> License Status
</a>
</div>
</div>
</div>
</div>
<!-- System Statistics -->
<div class="row mb-4">
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<i class="fas fa-users fa-2x text-primary mb-2"></i>
<h4 class="text-primary">{{ stats.total_users }}</h4>
<p class="text-muted mb-0">Total Users</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<i class="fas fa-project-diagram fa-2x text-success mb-2"></i>
<h4 class="text-success">{{ stats.total_projects }}</h4>
<p class="text-muted mb-0">Total Projects</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<i class="fas fa-clock fa-2x text-info mb-2"></i>
<h4 class="text-info">{{ stats.total_entries }}</h4>
<p class="text-muted mb-0">Time Entries</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<i class="fas fa-dollar-sign fa-2x text-warning mb-2"></i>
<h4 class="text-warning">{{ "%.1f"|format(stats.total_hours) }}h</h4>
<p class="text-muted mb-0">Total Hours</p>
</div>
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="row mb-4">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-user-cog"></i> User Management
</h5>
</div>
<div class="card-body">
<div class="d-grid gap-2">
<a href="{{ url_for('admin.list_users') }}" class="btn btn-outline-primary">
<i class="fas fa-users"></i> Manage Users
</a>
<a href="{{ url_for('admin.create_user') }}" class="btn btn-outline-success">
<i class="fas fa-user-plus"></i> Create New User
</a>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-cog"></i> System Settings
</h5>
</div>
<div class="card-body">
<div class="d-grid gap-2">
<a href="{{ url_for('admin.settings') }}" class="btn btn-outline-secondary">
<i class="fas fa-sliders-h"></i> Configure Settings
</a>
<a href="{{ url_for('admin.backup') }}" class="btn btn-outline-warning">
<i class="fas fa-download"></i> Create Backup
</a>
</div>
</div>
</div>
</div>
</div>
<!-- Recent Activity -->
<div class="row">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-history"></i> Recent Activity
</h5>
</div>
<div class="card-body">
{% if recent_entries %}
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>User</th>
<th>Project</th>
<th>Date</th>
<th>Duration</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{% for entry in recent_entries %}
<tr>
<td>{{ entry.user.username }}</td>
<td>
<a href="{{ url_for('projects.view_project', project_id=entry.project.id) }}">
{{ entry.project.name }}
</a>
</td>
<td>{{ entry.start_time.strftime('%Y-%m-%d %H:%M') }}</td>
<td>
<strong>{{ entry.duration_formatted }}</strong>
</td>
<td>
{% if entry.end_time %}
<span class="badge bg-success">Completed</span>
{% else %}
<span class="badge bg-warning">Running</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-4">
<i class="fas fa-clock fa-2x text-muted mb-3"></i>
<h5 class="text-muted">No Recent Activity</h5>
<p class="text-muted">No time entries have been recorded recently.</p>
</div>
{% endif %}
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-chart-pie"></i> System Overview
</h5>
</div>
<div class="card-body">
<div class="mb-3">
<h6>Active Users</h6>
<div class="progress mb-2">
<div class="progress-bar" role="progressbar"
style="width: {{ (stats.active_users / stats.total_users * 100) if stats.total_users > 0 else 0 }}%">
{{ stats.active_users }}/{{ stats.total_users }}
</div>
</div>
</div>
<div class="mb-3">
<h6>Active Projects</h6>
<div class="progress mb-2">
<div class="progress-bar bg-success" role="progressbar"
style="width: {{ (stats.active_projects / stats.total_projects * 100) if stats.total_projects > 0 else 0 }}%">
{{ stats.active_projects }}/{{ stats.total_projects }}
</div>
</div>
</div>
<div class="mb-3">
<h6>Billable Hours</h6>
<div class="progress mb-2">
<div class="progress-bar bg-warning" role="progressbar"
style="width: {{ (stats.billable_hours / stats.total_hours * 100) if stats.total_hours > 0 else 0 }}%">
{{ "%.1f"|format(stats.billable_hours) }}h/{{ "%.1f"|format(stats.total_hours) }}h
</div>
</div>
</div>
<div class="mt-4">
<h6>System Health</h6>
<div class="d-flex justify-content-between align-items-center">
<span>Database</span>
<span class="badge bg-success">Healthy</span>
</div>
<div class="d-flex justify-content-between align-items-center">
<span>Backup Status</span>
{% if stats.last_backup %}
<span class="badge bg-success">{{ stats.last_backup.strftime('%Y-%m-%d') }}</span>
{% else %}
<span class="badge bg-warning">No Backup</span>
{% endif %}
</div>
<div class="d-flex justify-content-between align-items-center">
<span>License Server</span>
<a href="{{ url_for('admin.license_status') }}" class="badge bg-info text-decoration-none">View Status</a>
</div>
</div>
</div>
</div>
<div class="card mt-3">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-tools"></i> Quick Actions
</h5>
</div>
<div class="card-body">
<div class="d-grid gap-2">
<a href="{{ url_for('projects.create_project') }}" class="btn btn-sm btn-outline-primary">
<i class="fas fa-plus"></i> New Project
</a>
<a href="{{ url_for('reports.reports') }}" class="btn btn-sm btn-outline-info">
<i class="fas fa-chart-line"></i> View Reports
</a>
<a href="{{ url_for('admin.system_info') }}" class="btn btn-sm btn-outline-secondary">
<i class="fas fa-info-circle"></i> System Info
</a>
<a href="{{ url_for('admin.license_status') }}" class="btn btn-sm btn-outline-info">
<i class="fas fa-key"></i> License Status
</a>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}