feat(frontend,backend): simple navigation bar added
This commit is contained in:
@@ -4,6 +4,21 @@ from typing import Dict
|
|||||||
|
|
||||||
web_router = APIRouter()
|
web_router = APIRouter()
|
||||||
|
|
||||||
|
# Navigation configuration - NEW TABS GO HERE!
|
||||||
|
NAVIGATION = [
|
||||||
|
{"name": "home", "label": "Home", "url": "/", "icon": "bi-house"},
|
||||||
|
{"name": "benchmark", "label": "Benchmark", "url": "/benchmark", "icon": "bi-hdd"},
|
||||||
|
{"name": "jobs", "label": "Job Queue", "url": "/jobs", "icon": "bi-list-task"},
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_active_tab(url: str) -> str:
|
||||||
|
"""Determine which navigation tab is active."""
|
||||||
|
for nav_item in NAVIGATION:
|
||||||
|
if nav_item["url"] == url:
|
||||||
|
return nav_item["name"]
|
||||||
|
return "home"
|
||||||
|
|
||||||
|
|
||||||
@web_router.get("/")
|
@web_router.get("/")
|
||||||
async def render_home(request: Request):
|
async def render_home(request: Request):
|
||||||
"""
|
"""
|
||||||
@@ -14,6 +29,37 @@ async def render_home(request: Request):
|
|||||||
name="index.html",
|
name="index.html",
|
||||||
request=request,
|
request=request,
|
||||||
context={
|
context={
|
||||||
"tools":tools
|
"tools":tools,
|
||||||
|
"navigation": NAVIGATION,
|
||||||
|
"active_tab": get_active_tab("/")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@web_router.get("/benchmark")
|
||||||
|
async def render_benchmark(request: Request):
|
||||||
|
"""Render the benchmark page."""
|
||||||
|
templates: Jinja2Templates = request.app.state.templates
|
||||||
|
|
||||||
|
return templates.TemplateResponse(
|
||||||
|
name="benchmark.html",
|
||||||
|
request=request,
|
||||||
|
context={
|
||||||
|
"navigation": NAVIGATION,
|
||||||
|
"active_tab": get_active_tab("/benchmark")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@web_router.get("/jobs")
|
||||||
|
async def render_jobs(request: Request):
|
||||||
|
"""Render the job queue page."""
|
||||||
|
templates: Jinja2Templates = request.app.state.templates
|
||||||
|
|
||||||
|
return templates.TemplateResponse(
|
||||||
|
name="jobs.html",
|
||||||
|
request=request,
|
||||||
|
context={
|
||||||
|
"navigation": NAVIGATION,
|
||||||
|
"active_tab": get_active_tab("/jobs")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
+32
-5
@@ -3,20 +3,47 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Disk Checker</title>
|
<title>Disk Checker - {% block title %}Home{% endblock %}</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
rel="stylesheet">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||||
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
|
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
|
||||||
<link rel="stylesheet" href="/static/css/style.css">
|
<link rel="stylesheet" href="/static/css/style.css">
|
||||||
|
{% block extra_css %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<!-- Navigation Bar -->
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand" href="/">Disk Checker</a>
|
<!-- Logo / Brand -->
|
||||||
|
<a class="navbar-brand" href="/">
|
||||||
|
<i class="bi bi-hdd-stack"></i>
|
||||||
|
Disk Checker
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Mobile toggle -->
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Navigation Tabs -->
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
{% for nav_item in navigation %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% if active_tab == nav_item.name %}active{% endif %}"
|
||||||
|
href="{{ nav_item.url }}">
|
||||||
|
<i class="bi {{ nav_item.icon }}"></i>
|
||||||
|
{{ nav_item.label }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="container">
|
<!-- Page Content -->
|
||||||
|
<div class="container mt-4">
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Benchmark{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<h2>Benchmark</h2>
|
||||||
|
<p class="text-muted">Configure and run disk benchmarks.</p>
|
||||||
|
|
||||||
|
<!-- Placeholder content - will be implemented later -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Select Drive</h5>
|
||||||
|
<p class="card-text">Choose a drive to benchmark from the list below.</p>
|
||||||
|
|
||||||
|
<!-- Drive selection will go here -->
|
||||||
|
<div id="drive-selector"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block title %}Home{% endblock %}
|
||||||
<div class="container mt-4">
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
<!--Available tools section-->
|
<!--Available tools section-->
|
||||||
<h2>Available Benchmarking Tools</h2>
|
<h2>Available Benchmarking Tools</h2>
|
||||||
|
|
||||||
@@ -37,9 +39,13 @@
|
|||||||
<i class="bi bi-info-circle"></i>
|
<i class="bi bi-info-circle"></i>
|
||||||
Mounted drives are grayed out and cannot be benchmarked.
|
Mounted drives are grayed out and cannot be benchmarked.
|
||||||
</p>
|
</p>
|
||||||
<div id="drives-list" hx-get="/api/v1/drives" hx-trigger="load" hx-target="#drives-content"></div>
|
<div id="drives-list"
|
||||||
|
hx-get="/api/v1/drives"
|
||||||
|
hx-trigger="load"
|
||||||
|
hx-target="#drives-content"></div>
|
||||||
<div id="drives-content" class="row"></div>
|
<div id="drives-content" class="row"></div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Job Queue{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<h2>Job Queue</h2>
|
||||||
|
<p class="text-muted">Monitor and manage benchmark jobs.</p>
|
||||||
|
|
||||||
|
<!-- Jobs list -->
|
||||||
|
<div id="jobs-list"
|
||||||
|
hx-get="/api/v1/jobs"
|
||||||
|
hx-trigger="load"
|
||||||
|
hx-target="#jobs-content">
|
||||||
|
<p>Loading jobs...</p>
|
||||||
|
</div>
|
||||||
|
<div id="jobs-content"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_js %}
|
||||||
|
<script>
|
||||||
|
// Load jobs when page loads
|
||||||
|
document.addEventListener('htmx:afterRequest', function(evt) {
|
||||||
|
if (evt.detail.target.id === 'jobs-content') {
|
||||||
|
renderJobs(JSON.parse(evt.detail.xhr.response));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function renderJobs(jobIds) {
|
||||||
|
const container = document.getElementById('jobs-content');
|
||||||
|
container.innerHTML = '';
|
||||||
|
|
||||||
|
if (!jobIds || jobIds.length === 0) {
|
||||||
|
container.innerHTML = '<div class="alert alert-info">No jobs in queue.</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jobIds.forEach(jobId => {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.className = 'card mb-2';
|
||||||
|
div.innerHTML = `
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">${jobId}</h5>
|
||||||
|
<p class="card-text text-muted">Job details will appear here...</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
container.appendChild(div);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user