feat: add dashboard route, template, and styles for project and scenario insights

This commit is contained in:
2025-11-09 18:50:00 +01:00
parent 02da881d3e
commit 053da332ac
6 changed files with 453 additions and 45 deletions

130
templates/Dashboard.html Normal file
View File

@@ -0,0 +1,130 @@
{% extends "base.html" %}
{% block title %}Dashboard · CalMiner{% endblock %}
{% block head_extra %}
<link rel="stylesheet" href="/static/css/dashboard.css" />
{% endblock %}
{% block content %}
<section class="page-header dashboard-header">
<div>
<h1>Welcome back</h1>
<p class="page-subtitle">Monitor project progress and scenario insights at a glance.</p>
</div>
<div class="header-actions">
<a class="btn primary" href="{{ url_for('projects.create_project_form') }}">New Project</a>
<a class="btn" href="#">Import Data</a>
</div>
</section>
<section class="dashboard-metrics">
<article class="metric-card">
<h2>Total Projects</h2>
<p class="metric-value">{{ metrics.total_projects }}</p>
<span class="metric-caption">Across all operation types</span>
</article>
<article class="metric-card">
<h2>Active Scenarios</h2>
<p class="metric-value">{{ metrics.active_scenarios }}</p>
<span class="metric-caption">Ready for analysis</span>
</article>
<article class="metric-card">
<h2>Pending Simulations</h2>
<p class="metric-value">{{ metrics.pending_simulations }}</p>
<span class="metric-caption">Awaiting execution</span>
</article>
<article class="metric-card">
<h2>Last Data Import</h2>
<p class="metric-value">{{ metrics.last_import or '—' }}</p>
<span class="metric-caption">UTC timestamp</span>
</article>
</section>
<section class="dashboard-grid">
<div class="grid-main">
<div class="card">
<header class="card-header">
<h2>Recent Projects</h2>
<a class="btn btn-link" href="{{ url_for('projects.project_list_page') }}">View all</a>
</header>
{% if recent_projects %}
<table class="table">
<thead>
<tr>
<th>Project</th>
<th>Operation</th>
<th>Updated</th>
</tr>
</thead>
<tbody>
{% for project in recent_projects %}
<tr>
<td>
<a class="table-link" href="{{ url_for('projects.view_project', project_id=project.id) }}">{{ project.name }}</a>
</td>
<td>{{ project.operation_type.value.replace('_', ' ') | title }}</td>
<td>{{ project.updated_at.strftime('%Y-%m-%d') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="empty-state">No recent projects. <a href="{{ url_for('projects.create_project_form') }}">Create one now.</a></p>
{% endif %}
</div>
<div class="card">
<header class="card-header">
<h2>Simulation Pipeline</h2>
</header>
{% if simulation_updates %}
<ul class="timeline">
{% for update in simulation_updates %}
<li>
<span class="timeline-label">{{ update.timestamp.strftime('%Y-%m-%d %H:%M') }}</span>
<div>
<strong>{{ update.title }}</strong>
<p>{{ update.description }}</p>
</div>
</li>
{% endfor %}
</ul>
{% else %}
<p class="empty-state">No simulation runs yet. Configure a scenario to start simulations.</p>
{% endif %}
</div>
</div>
<aside class="grid-sidebar">
<div class="card">
<header class="card-header">
<h2>Scenario Alerts</h2>
</header>
{% if scenario_alerts %}
<ul class="alerts-list">
{% for alert in scenario_alerts %}
<li>
<strong>{{ alert.title }}</strong>
<p>{{ alert.message }}</p>
<a class="btn btn-link" href="{{ alert.link }}">Review</a>
</li>
{% endfor %}
</ul>
{% else %}
<p class="empty-state">All scenarios look good. We'll highlight issues here.</p>
{% endif %}
</div>
<div class="card">
<header class="card-header">
<h2>Resources</h2>
</header>
<ul class="links-list">
<li><a href="https://github.com/" target="_blank">CalMiner Repository</a></li>
<li><a href="https://example.com/docs" target="_blank">Documentation</a></li>
<li><a href="mailto:support@example.com">Contact Support</a></li>
</ul>
</div>
</aside>
</section>
{% endblock %}

View File

@@ -1,10 +1,10 @@
<div class="sidebar-inner">
<div class="sidebar-brand">
<a class="sidebar-brand" href="{{ request.url_for('dashboard.home') }}">
<span class="brand-logo" aria-hidden="true">CM</span>
<div class="brand-text">
<span class="brand-title">CalMiner</span>
<span class="brand-subtitle">Mining Planner</span>
</div>
</div>
</a>
{% include "partials/sidebar_nav.html" %}
</div>

View File

@@ -1,49 +1,80 @@
{% set nav_groups = [ { "label": "Dashboard", "links": [ {"href": "/", "label":
"Dashboard"}, ], }, { "label": "Overview", "links": [ {"href": "/ui/parameters",
"label": "Parameters"}, {"href": "/ui/costs", "label": "Costs"}, {"href":
"/ui/consumption", "label": "Consumption"}, {"href": "/ui/production", "label":
"Production"}, { "href": "/ui/equipment", "label": "Equipment", "children": [
{"href": "/ui/maintenance", "label": "Maintenance"}, ], }, ], }, { "label":
"Simulations", "links": [ {"href": "/ui/simulations", "label": "Simulations"},
], }, { "label": "Analytics", "links": [ {"href": "/ui/reporting", "label":
"Reporting"}, ], }, { "label": "Settings", "links": [ { "href": "/ui/settings",
"label": "Settings", "children": [ {"href": "/theme-settings", "label":
"Themes"}, {"href": "/ui/currencies", "label": "Currency Management"}, ], }, ],
}, ] %}
{% set dashboard_href = request.url_for('dashboard.home') if request else '/' %}
{% set projects_href = request.url_for('projects.project_list_page') if request else '/projects/ui' %}
{% set project_create_href = request.url_for('projects.create_project_form') if request else '/projects/create' %}
{% set nav_groups = [
{
"label": "Workspace",
"links": [
{"href": dashboard_href, "label": "Dashboard", "match_prefix": "/"},
{"href": projects_href, "label": "Projects", "match_prefix": "/projects"},
{"href": project_create_href, "label": "New Project", "match_prefix": "/projects/create"},
],
},
{
"label": "Insights",
"links": [
{"href": "/ui/simulations", "label": "Simulations"},
{"href": "/ui/reporting", "label": "Reporting"},
],
},
{
"label": "Configuration",
"links": [
{
"href": "/ui/settings",
"label": "Settings",
"children": [
{"href": "/theme-settings", "label": "Themes"},
{"href": "/ui/currencies", "label": "Currency Management"},
],
},
],
},
] %}
<nav class="sidebar-nav" aria-label="Primary navigation">
{% set current_path = request.url.path if request else "" %} {% for group in
nav_groups %}
<div class="sidebar-section">
<div class="sidebar-section-label">{{ group.label }}</div>
<div class="sidebar-section-links">
{% for link in group.links %} {% set href = link.href %} {% if href == "/"
%} {% set is_active = current_path == "/" %} {% else %} {% set is_active =
current_path.startswith(href) %} {% endif %}
<div class="sidebar-link-block">
<a
href="{{ href }}"
class="sidebar-link{% if is_active %} is-active{% endif %}"
>
{{ link.label }}
</a>
{% if link.children %}
<div class="sidebar-sublinks">
{% for child in link.children %} {% if child.href == "/" %} {% set
child_active = current_path == "/" %} {% else %} {% set child_active =
current_path.startswith(child.href) %} {% endif %}
<a
href="{{ child.href }}"
class="sidebar-sublink{% if child_active %} is-active{% endif %}"
>
{{ child.label }}
</a>
{% endfor %}
</div>
{% endif %}
{% set current_path = request.url.path if request else "" %}
{% for group in nav_groups %}
<div class="sidebar-section">
<div class="sidebar-section-label">{{ group.label }}</div>
<div class="sidebar-section-links">
{% for link in group.links %}
{% set href = link.href %}
{% set match_prefix = link.get('match_prefix', href) %}
{% if match_prefix == '/' %}
{% set is_active = current_path == '/' %}
{% else %}
{% set is_active = current_path.startswith(match_prefix) %}
{% endif %}
<div class="sidebar-link-block">
<a
href="{{ href }}"
class="sidebar-link{% if is_active %} is-active{% endif %}"
>
{{ link.label }}
</a>
{% if link.children %}
<div class="sidebar-sublinks">
{% for child in link.children %}
{% set child_prefix = child.get('match_prefix', child.href) %}
{% if child_prefix == '/' %}
{% set child_active = current_path == '/' %}
{% else %}
{% set child_active = current_path.startswith(child_prefix) %}
{% endif %}
<a
href="{{ child.href }}"
class="sidebar-sublink{% if child_active %} is-active{% endif %}"
>
{{ child.label }}
</a>
{% endfor %}
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</nav>