Improvement: Add frontend, Many more improvements and small bugfixes

Bump to version 0.1.0
This commit is contained in:
Filip Bednárik
2024-12-15 03:38:50 +01:00
parent 4e1f6be840
commit 32f90cfe84
21 changed files with 2746 additions and 181 deletions

72
templates/assign_tag.html Normal file
View File

@ -0,0 +1,72 @@
{% extends 'base.html' %}
{% block content %}
<!-- Page Title -->
<h1 class="mb-4 text-center">Assign NFC Tag to Spool</h1>
<!-- Empty State -->
{% if spools|length == 0 or not spools %}
<div class="alert alert-info text-center" role="alert">
No spools available to tag at the moment.
</div>
{% else %}
<!-- Spool List -->
<div class="list-group">
{% for spool in spools %}
{% if not spool.extra.get("tag") or spool.extra.get("tag") == "null" %}
<!-- Individual Spool Item -->
<a href="{{ url_for('write_tag', spool_id=spool.id) }}"
class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
<!-- Left: Filament Color Badge -->
<div class="me-3">
<span class="badge d-inline-block"
style="background-color: #{{ spool.filament.color_hex }}; width: 20px; height: 50px;">
</span>
</div>
<!-- Middle: Filament Details -->
<div class="flex-grow-1">
<!-- Vendor Name and Material (Row 1) -->
<h6 class="mb-0">{{ spool.filament.vendor.name }} - {{ spool.filament.material }}</h6>
<!-- Filament Name (Row 2) -->
<small class="text-muted">{{ spool.filament.name }}</small>
</div>
<!-- Action Icon -->
<span class="badge bg-primary rounded-pill">
<i class="bi bi-plus-circle"></i> Assign
</span>
</a>
{% endif %}
{% endfor %}
{% for spool in spools %}
{% if spool.extra.get("tag") %}
<!-- Individual Spool Item -->
<a href="{{ url_for('write_tag', spool_id=spool.id) }}"
class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
<!-- Left: Filament Color Badge -->
<div class="me-3">
<span class="badge d-inline-block"
style="background-color: #{{ spool.filament.color_hex }}; width: 20px; height: 50px;">
</span>
</div>
<!-- Middle: Filament Details -->
<div class="flex-grow-1">
<!-- Vendor Name and Material (Row 1) -->
<h6 class="mb-0">{{ spool.filament.vendor.name }} - {{ spool.filament.material }}</h6>
<!-- Filament Name (Row 2) -->
<small class="text-muted">{{ spool.filament.name }}</small>
</div>
<!-- Action Icon -->
<span class="badge bg-secondary rounded-pill">
<i class="bi bi-plus-circle"></i> Reassign
</span>
</a>
{% endif %}
{% endfor %}
</div>
{% endif %}
{% endblock %}

72
templates/base.html Normal file
View File

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html lang="en" data-bs-theme="auto">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>OpenSpoolMan</title>
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/bootstrap-icons.css') }}" rel="stylesheet">
<style>
.bi {
vertical-align: -.125em;
fill: currentColor;
}
.bd-mode-toggle .dropdown-menu .active .bi {
display: block !important;
}
</style>
</head>
<body>
<header class="p-1 mb-3 border-bottom">
<div class="container">
<div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start">
<a href="{{ url_for('home') }}" class="d-flex align-items-center mb-2 mb-lg-0 link-body-emphasis text-decoration-none">
<img width="40" height="40" alt="OpenSpoolMan Logo" src="{{ url_for('static', filename='logo.png') }}"/>
</a>
<ul class="nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0">
<li><a href="{{ url_for('home') }}" class="nav-link px-2 link-body-emphasis">Home</a></li>
<li><a href="{{ url_for('assign_tag') }}" class="nav-link px-2 link-body-emphasis">Assign NFC Tag</a></li>
</ul>
</div>
</div>
</header>
<main class="container">
{% if success_message %}
<div class="alert alert-success alert-dismissible fade show" role="alert">
<strong>Success!</strong> {{ success_message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endif %}
{% block content %}{% endblock %}
</main>
<div class="container">
<footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top">
<ul class="nav col-md-12 justify-content-end list-unstyled d-flex">
<li class="ms-3"><a class="link-body-emphasis" href="https://github.com/drndos/openspoolman">
<i class="bi bi-github"></i>
</a></li>
</ul>
</footer>
</div>
<script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script>
<script>
;(function () {
const htmlElement = document.querySelector("html")
if (htmlElement.getAttribute("data-bs-theme") === 'auto') {
function updateTheme() {
document.querySelector("html").setAttribute("data-bs-theme",
window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light")
}
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', updateTheme)
updateTheme()
}
})()
</script>
</body>
</html>

6
templates/error.html Normal file
View File

@ -0,0 +1,6 @@
{% extends 'base.html' %}
{% block content %}
<h1>Error</h1>
<p>{{ exception }}</p>
{% endblock %}

138
templates/index.html Normal file
View File

@ -0,0 +1,138 @@
{% extends 'base.html' %}
{% block content %}
<h1 class="mb-4">Info</h1>
{% if issue %}
<div class="card border-warning shadow-sm mb-4">
<div class="card-header bg-warning text-dark fw-bold">
Warning
</div>
<div class="card-body">
<h5 class="card-title">There is a mismatch between printer and SpoolMan</h5>
<p class="card-text">TODO: To fix the issue click on the tray with the red exclamation mark <i class="bi bi-exclamation-circle text-danger me-2"></i></p>
</div>
</div>
{% endif %}
<!-- AMS and External Spool Row -->
<div class="row">
<!-- External Spool -->
<div class="col-md-2 mb-4">
<div class="card shadow-sm">
<div class="card-header">
<h5 class="mb-0">External Spool</h5>
</div>
<div class="card-body text-center">
<!-- Tray ID -->
<h6 class="text-uppercase mb-1">
{% if vt_tray_data.issue %}
<i class="bi bi-exclamation-circle text-danger me-2"></i>
{% endif %}
{% if not vt_tray_data.tray_type %}
Empty
{% endif %}
Tray {{ vt_tray_data.id }}
</h6>
<!-- Tray Sub-Brand and Type -->
<div class="small text-muted mb-2">
{{ vt_tray_data.tray_type }}
{% if vt_tray_data.tray_sub_brands %}
<br/>
{{ vt_tray_data.tray_sub_brands }}
{% endif %}
</div>
<!-- Badge with Dynamic Colors -->
<span class="badge d-inline-block p-2"
style="background-color: #{{ vt_tray_data.tray_color }};
color: {% if color_is_dark(vt_tray_data.tray_color) %}#FFFFFF{% else %}#000000{% endif %}">
#{{ vt_tray_data.tray_color | upper }}
</span>
<!-- Remaining Percentage -->
<div class="mt-2">
Remaining:
{% if AUTO_SPEND and vt_tray_data.matched %}
<span class="fw-bold">{{ vt_tray_data.remaining_weight|round }}g</span>
{% else %}
<span class="fw-bold">{{ vt_tray_data.remain }}%</span>
{% endif %}
</div>
</div>
</div>
</div>
{% for ams in ams_data %}
<div class="col-md-4 mb-4">
<div class="card shadow-sm">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">AMS {{ ams.id }}</h5>
<span class="text-muted small">Humidity: {{ ams.humidity }}%, Temp: {{ ams.temp }}°C</span>
</div>
<div class="card-body">
<div class="row">
{% for tray in ams.tray %}
<div class="col-6 mb-3">
<div class="border rounded p-2 text-center">
<!-- Tray ID -->
<h6 class="text-uppercase mb-1">
{% if tray.issue %}
<i class="bi bi-exclamation-circle text-danger me-2"></i>
{% endif %}
{% if not tray.tray_type %}
Empty
{% endif %}
Tray {{ tray.id }}
</h6>
<!-- Tray Sub-Brand and Type -->
<div class="small text-muted mb-2">
{{ tray.tray_type }}
{% if tray.tray_sub_brands %}
<br/>
{{ tray.tray_sub_brands }}
{% endif %}
</div>
{% if tray.tray_color %}
<!-- Badge with Dynamic Colors -->
<span class="badge d-inline-block p-2"
style="background-color: #{{ tray.tray_color }};
color: {% if color_is_dark(tray.tray_color) %}#FFFFFF{% else %}#000000{% endif %}">
#{{ tray.tray_color | upper }}
</span>
{% endif %}
<!-- Remaining Percentage -->
<div class="mt-2">
Remaining:
{% if AUTO_SPEND and tray.matched %}
<span class="fw-bold">{{ tray.remaining_weight|round }}g</span>
{% else %}
<span class="fw-bold">{{ tray.remain }}%</span>
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<!-- Instruction Section -->
<div class="card shadow-sm mb-4">
<div class="card-body">
<h5 class="card-title mb-3">
<i class="bi bi-info-circle text-info me-2"></i> Instructions
</h5>
<ul class="list-unstyled">
<li>Assign NFC Tags to your spools
</li>
<li>Load the spool with NFC tag to your AMS and bring your phone close to the NFC tag, open the URL.</li>
<li>Choose the tray you just put the spool in.</li>
</ul>
</div>
</div>
{% endblock %}

144
templates/spool_info.html Normal file
View File

@ -0,0 +1,144 @@
{% extends 'base.html' %}
{% block content %}
<h1 class="mb-4">Spool Info</h1>
<div class="card mb-3 shadow-sm">
<div class="card-header fw-bold">
Spool Details
</div>
<div class="card-body">
<!-- Filament Color Badge and Name -->
<div class="d-flex align-items-start mb-3">
<div class="me-3">
<span class="badge d-inline-block"
style="background-color: #{{ current_spool.filament.color_hex }}; width: 40px; height: 40px; border-radius: 5px;">
</span>
</div>
<div>
<h5 class="card-title mb-0">{{ current_spool.filament.name }} - {{ current_spool.filament.material }}</h5>
<small class="text-muted">{{ current_spool.filament.vendor.name }}</small>
</div>
</div>
<!-- Filament Details -->
<div class="row mb-2">
<div class="col-6">
<p class="mb-1"><strong>Remaining Weight:</strong> {{ current_spool.remaining_weight|round(2) }}g</p>
<p class="mb-1"><strong>Remaining Length:</strong> {{ current_spool.remaining_length|round(0) }}mm</p>
</div>
<div class="col-6">
<p class="mb-1"><strong>Nozzle Temp:</strong> {{ current_spool.filament.extra.nozzle_temperature }}</p>
</div>
</div>
</div>
<div class="card-footer text-muted">
<small>Registered: {{ current_spool.registered }} | Last Used: {{ current_spool.last_used }}</small>
</div>
</div>
<h1 class="mb-4">Pick Tray</h1>
<!-- AMS and External Spool Row -->
<div class="row">
<!-- External Spool -->
<div class="col-md-2 mb-4">
<div class="card shadow-sm">
<div class="card-header">
<h5 class="mb-0">External Spool</h5>
</div>
<div class="card-body text-center">
<div class="card">
<!-- Tray ID -->
<div class="card-header d-flex justify-content-between align-items-center">
{% if vt_tray_data.issue %}
<i class="bi bi-exclamation-circle text-danger me-2"></i>
{% endif %}
{% if not vt_tray_data.tray_type %}
Empty
{% endif %}
Tray {{ vt_tray_data.id }}
</div>
<div class="card-body">
<!-- Tray Sub-Brand and Type -->
<div class="small text-muted mb-2">
{{ vt_tray_data.tray_type }}
{% if vt_tray_data.tray_sub_brands %}
<br/>
{{ vt_tray_data.tray_sub_brands }}
{% endif %}
</div>
<!-- Badge with Dynamic Colors -->
<span class="badge d-inline-block p-2"
style="background-color: #{{ vt_tray_data.tray_color }};
color: {% if color_is_dark(vt_tray_data.tray_color) %}#FFFFFF{% else %}#000000{% endif %}">
#{{ vt_tray_data.tray_color | upper }}
</span>
</div>
<div class="card-footer">
<a class="btn btn-primary"
href="{{ url_for('tray_load', spool_id=current_spool['id'], tag_id=tag_id,ams=vt_tray_data['id'], tray='255') }}">Pick
this tray</a>
</div>
</div>
</div>
</div>
</div>
{% for ams in ams_data %}
<div class="col-md-4 mb-4">
<div class="card shadow-sm">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">AMS {{ ams.id }}</h5>
<span class="text-muted small">Humidity: {{ ams.humidity }}%, Temp: {{ ams.temp }}°C</span>
</div>
<div class="card-body">
<div class="row">
{% for tray in ams.tray %}
<div class="col-6 mb-3">
<div class="card">
<!-- Tray ID -->
<div class="card-header d-flex justify-content-between align-items-center">
{% if tray.issue %}
<i class="bi bi-exclamation-circle text-danger me-2"></i>
{% endif %}
{% if not tray.tray_type %}
Empty
{% endif %}
Tray {{ tray.id }}
</div>
<div class="card-body">
<!-- Tray Sub-Brand and Type -->
<div class="small text-muted mb-2">
{{ tray.tray_type }}
{% if tray.tray_sub_brands %}
<br/>
{{ tray.tray_sub_brands }}
{% endif %}
</div>
{% if tray.tray_color %}
<!-- Badge with Dynamic Colors -->
<span class="badge d-inline-block p-2"
style="background-color: #{{ tray.tray_color }};
color: {% if color_is_dark(tray.tray_color) %}#FFFFFF{% else %}#000000{% endif %}">
#{{ tray.tray_color | upper }}
</span>
{% endif %}
</div>
<div class="card-footer">
<a class="btn btn-primary"
href="{{ url_for('tray_load', spool_id=current_spool['id'], tag_id=tag_id,ams=ams['id'], tray=tray['id']) }}">Pick
this tray</a>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}

62
templates/write_tag.html Normal file
View File

@ -0,0 +1,62 @@
{% extends 'base.html' %}
{% block content %}
<!-- Page Title -->
<div class="text-center mb-4">
<h1 class="fw-bold">NFC Write Process</h1>
<p class="text-muted">Follow the steps below to write data to your NFC tag.</p>
</div>
<!-- Instruction Section -->
<div class="card shadow-sm mb-4">
<div class="card-body">
<h5 class="card-title mb-3">
<i class="bi bi-info-circle text-info me-2"></i> Instructions
</h5>
<ul class="list-unstyled">
<li><i class="bi bi-check-circle-fill text-success me-2"></i> Attach NFC tag to spool so you can reach it with the
top of your phone.
</li>
<li><i class="bi bi-wifi text-primary me-2"></i> Allow NFC usage if prompted.</li>
<li><i class="bi bi-phone text-secondary me-2"></i> Bring the tag close to your phone when prompted.</li>
</ul>
</div>
</div>
<!-- Action Button -->
<div class="text-center mb-3">
<button id="write" class="btn btn-lg btn-primary shadow" onclick="writeNFC()">
<i class="bi bi-nfc me-2"></i> Start Writing NFC Tag
</button>
</div>
<!-- Message Display -->
<div id="message" class="alert alert-secondary text-center" role="alert">
Press "Start Writing NFC Tag" to begin.
</div>
<script type="text/javascript">
function writeNFC() {
// Update user message
const messageBox = document.getElementById("message");
messageBox.className = "alert alert-info text-center";
messageBox.textContent = "Bring NFC Tag closer to the phone...";
if ('NDEFReader' in window) {
const ndef = new NDEFReader();
// Attempt to write the NFC tag
ndef.write({
records: [{recordType: "url", data: "{{ BASE_URL }}/spool_info?tag_id={{ myuuid }}"}],
}).then(() => {
messageBox.className = "alert alert-success text-center";
messageBox.textContent = "✅ Message successfully written to the NFC tag!";
}).catch(error => {
messageBox.className = "alert alert-danger text-center";
messageBox.textContent = "❌ Write failed. Please try again: " + error;
});
} else {
messageBox.className = "alert alert-danger text-center";
messageBox.textContent = "Your browser or device does not support NFC writing. Try Android Phone with Chrome browser.";
}
}
</script>
{% endblock %}