Grotti 3.6.1: Abgebrochene Läufe bleiben im Protokoll, Spulenwechsel bucht den laufenden Druck nicht vorzeitig ab, und der Pi öffnet große Dateien nicht mehr parallel.

This commit is contained in:
Dominic Gundel committed 2026-11-01 18:56:14 +01:00
1 parent 2b1e36634a
commit 5081212212
23 files changed
+559 -65

No files matched your search

+10 -1
View File
@@ -2485,6 +2485,15 @@ def create_app(cfg):
for row in old:
store.open_segment(conn(), live_run["id"], row["id"], slot, 0)
store.close_open_segments(conn(), live_run["id"], slot, mm_now)
elif not closed and mm_now > 0:
# ACE ohne Startabschnitt oder alte Rolle schon im Regal —
# slot-genau: Platz / ACE-Map / letzter Abschnitt / Lauf-Hinweis.
prev_id = store.prev_spool_id_for_slot(
conn(), host, slot, live_run, spool_id, old_rows=old,
)
if prev_id:
store.open_segment(conn(), live_run["id"], prev_id, slot, 0)
store.close_open_segments(conn(), live_run["id"], slot, mm_now)
for row in old:
store.update_spool(conn(), row["id"], {"printer_host": "", "ace_slot": None})
store.add_event(
@@ -2717,7 +2726,7 @@ def create_app(cfg):
"samples": samples,
"labels": store.list_run_labels(conn(), run_id),
"events": store.list_run_events(conn(), run_id),
"file": store.file_out(file_row, watch_dir=cfg.get("watch_dir")) if file_row else None,
"file": store.file_out(file_row, watch_dir=cfg.get("watch_dir"), conn=conn()) if file_row else None,
"project": project,
"energy": energy,
})
+46 -14
View File
@@ -64,8 +64,8 @@
--st-error-soft: rgba(248, 113, 113, 0.14);
--st-offline: #71717a;
--st-offline-soft: rgba(255, 255, 255, 0.04);
--st-waiting: #f97316;
--st-waiting-soft: rgba(249, 115, 22, 0.14);
--st-waiting: #f59e0b;
--st-waiting-soft: rgba(245, 158, 11, 0.16);
--st-idle: #a1a1aa;
--st-idle-soft: rgba(255, 255, 255, 0.05);
--ease: cubic-bezier(0.2, 0.7, 0.2, 1);
@@ -105,8 +105,8 @@ html[data-theme="light"] {
--st-error-soft: rgba(220, 38, 38, 0.1);
--st-offline: #73737c;
--st-offline-soft: rgba(0, 0, 0, 0.04);
--st-waiting: #ea580c;
--st-waiting-soft: rgba(234, 88, 12, 0.1);
--st-waiting: #b45309;
--st-waiting-soft: rgba(180, 83, 9, 0.12);
--st-idle: #5c5c66;
--st-idle-soft: rgba(0, 0, 0, 0.04);
}
@@ -124,14 +124,14 @@ body {
font: 14.5px/1.45 var(--font);
color: var(--ink);
background:
radial-gradient(900px 420px at 0% 0%, rgba(249, 115, 22, 0.07), transparent 55%),
radial-gradient(1100px 520px at 0% 0%, rgba(249, 115, 22, 0.14), transparent 58%),
var(--bg);
-webkit-font-smoothing: antialiased;
font-feature-settings: "cv11", "ss01";
}
html[data-theme="light"] body {
background:
radial-gradient(900px 420px at 0% 0%, rgba(234, 88, 12, 0.06), transparent 55%),
radial-gradient(1100px 520px at 0% 0%, rgba(234, 88, 12, 0.11), transparent 58%),
var(--bg);
}
.tabular, .num, .hero-main, .hero-side, .stat b, .chip, .count, .run-line-text, time {
@@ -298,6 +298,8 @@ html.shelf .hero-main,
html.shelf [data-role="hero"],
body.shelf .hero-main,
body.shelf [data-role="hero"] { font-size: 1.35rem; }
html.shelf article.machine.printing .hero-main,
body.shelf article.machine.printing .hero-main { font-size: 2.4rem; }
.mobile-nav .nav-shelf { display: none; }
@media (max-height: 900px) {
@@ -1015,7 +1017,7 @@ article.machine {
background: linear-gradient(180deg, rgba(255, 255, 255, 0.03), transparent 40%), var(--card);
border: 1px solid var(--line);
border-radius: var(--radius);
box-shadow: var(--shadow);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), var(--shadow);
overflow: hidden;
display: flex;
flex-direction: column;
@@ -1023,6 +1025,9 @@ article.machine {
cursor: pointer;
transition: border-color 0.3s var(--ease), box-shadow 0.3s var(--ease), transform 0.2s var(--ease);
}
html[data-theme="light"] article.machine {
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9), var(--shadow);
}
article.machine::before {
content: "";
position: absolute;
@@ -1032,12 +1037,31 @@ article.machine::before {
}
article.machine:hover {
border-color: var(--line-strong);
box-shadow: var(--shadow), 0 0 0 1px rgba(255, 255, 255, 0.04);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08), var(--shadow), 0 0 0 1px rgba(255, 255, 255, 0.04);
transform: translateY(-1px);
}
article.machine.printing { border-color: rgba(61, 206, 124, 0.35); box-shadow: var(--shadow), 0 0 0 1px rgba(61, 206, 124, 0.06), 0 18px 40px -24px rgba(61, 206, 124, 0.45); }
article.machine.printing::before { background: linear-gradient(90deg, transparent, var(--st-printing), transparent); opacity: 0.7; }
article.machine.printing:hover { border-color: rgba(61, 206, 124, 0.55); box-shadow: var(--shadow), 0 0 0 1px rgba(61, 206, 124, 0.12), 0 18px 40px -20px rgba(61, 206, 124, 0.55); }
html[data-theme="light"] article.machine:hover {
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.95), var(--shadow), 0 0 0 1px rgba(0, 0, 0, 0.04);
}
article.machine.printing {
border-color: rgba(61, 206, 124, 0.35);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), var(--shadow), 0 0 0 1px rgba(61, 206, 124, 0.06), 0 18px 40px -24px rgba(61, 206, 124, 0.45);
}
article.machine.printing::before {
background: linear-gradient(90deg, transparent, var(--st-printing), transparent);
opacity: 0.7;
animation: print-strip-breathe 2.8s var(--ease) infinite;
}
article.machine.printing:hover {
border-color: rgba(61, 206, 124, 0.55);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08), var(--shadow), 0 0 0 1px rgba(61, 206, 124, 0.12), 0 18px 40px -20px rgba(61, 206, 124, 0.55);
}
article.machine.printing .hero-main {
font-size: 2.4rem;
letter-spacing: -0.05em;
font-variant-numeric: tabular-nums;
line-height: 1.05;
}
article.machine.paused { border-color: rgba(251, 191, 36, 0.35); }
article.machine.paused:hover { border-color: rgba(251, 191, 36, 0.55); }
article.machine.heating { border-color: rgba(251, 191, 36, 0.28); }
@@ -1047,6 +1071,10 @@ article.machine.error::before { background: var(--st-error); opacity: 0.7; }
article.machine.error:hover { border-color: rgba(248, 113, 113, 0.6); }
article.machine.offline { opacity: 0.62; }
article.machine.offline:hover { opacity: 1; }
@keyframes print-strip-breathe {
0%, 100% { opacity: 0.45; }
50% { opacity: 0.9; }
}
.machine-head {
padding: 0.85rem 0.95rem 0.3rem;
@@ -1480,7 +1508,7 @@ td select { width: auto; min-width: 8.5rem; padding: 0.3rem 0.45rem; min-height:
place-items: center;
padding: 1.5rem;
background:
radial-gradient(ellipse at 20% 0%, rgba(61, 206, 124, 0.12), transparent 45%),
radial-gradient(ellipse at 20% 0%, rgba(249, 115, 22, 0.16), transparent 50%),
var(--bg);
}
.auth-card {
@@ -1489,6 +1517,10 @@ td select { width: auto; min-width: 8.5rem; padding: 0.3rem 0.45rem; min-height:
border: 1px solid var(--line);
border-radius: var(--radius);
padding: 1.4rem 1.35rem 1.5rem;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), var(--shadow);
}
html[data-theme="light"] .auth-card {
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9), var(--shadow);
}
.auth-card h1 { margin: 0 0 0.35rem; font-size: 1.45rem; }
.auth-brand {
@@ -2189,7 +2221,7 @@ body.desk-on main {
.chip.complete { --c: var(--st-done); --cs: var(--st-done-soft); }
.chip.error { --c: var(--st-error); --cs: var(--st-error-soft); }
.chip.offline { --c: var(--st-offline); --cs: var(--st-offline-soft); }
.chip.waiting { --c: var(--st-waiting); --cs: transparent; box-shadow: inset 0 0 0 1px rgba(249, 115, 22, 0.45); }
.chip.waiting { --c: var(--st-waiting); --cs: transparent; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-waiting) 45%, transparent); }
.chip.cancelled { --c: var(--muted); --cs: var(--st-idle-soft); }
.chip.sm { font-size: 0.6rem; padding: 0.12rem 0.45rem 0.12rem 0.38rem; gap: 0.3rem; }
.chip.sm::before { width: 0.36rem; height: 0.36rem; }
@@ -2329,7 +2361,7 @@ body.desk-on main {
.strip.stopped .strip-actions button:not(.ghost) { background: var(--accent); color: var(--accent-ink); }
.strip.stopped .strip-actions button.ghost { color: #fecaca; border-color: rgba(248, 113, 113, 0.4); }
.waiting-note { font-size: var(--t-xs); color: var(--muted); display: flex; align-items: center; gap: 0.35rem; }
.waiting-note b { color: var(--accent); }
.waiting-note b { color: var(--st-waiting); }
.desk-next {
margin-top: 0.65rem;
padding: 0.55rem 0.6rem;
+1 -1
View File
@@ -9,7 +9,7 @@
<link rel="icon" type="image/png" sizes="32x32" href="{{ url_for('static', filename='brand/favicon-32.png') }}">
<link rel="icon" type="image/png" sizes="512x512" href="{{ url_for('static', filename='brand/favicon.png') }}">
<link rel="apple-touch-icon" href="{{ url_for('static', filename='brand/apple-touch-icon.png') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='grotti.css') }}?v=73">
<link rel="stylesheet" href="{{ url_for('static', filename='grotti.css') }}?v=75">
<link rel="manifest" href="{{ url_for('static', filename='manifest.webmanifest') }}">
<meta name="theme-color" content="#0a0a0c" id="theme-color-meta">
<script>
+1 -1
View File
@@ -6,7 +6,7 @@
<meta name="csrf" content="{{ csrf }}">
<title>Anmelden · Grotti</title>
<link rel="icon" type="image/png" sizes="32x32" href="{{ url_for('static', filename='brand/favicon-32.png') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='grotti.css') }}?v=62">
<link rel="stylesheet" href="{{ url_for('static', filename='grotti.css') }}?v=75">
</head>
<body class="auth-body">
<main class="auth-card">
+1 -1
View File
@@ -1580,7 +1580,7 @@ function sortPrinters(printers) {
async function refresh() {
if (!libraryFiles.length) {
try { libraryFiles = await api("/dateien"); } catch (error) { libraryFiles = []; }
api("/dateien").then((rows) => { libraryFiles = rows || []; }).catch(() => {});
}
if (!wallSpools.length || deskHost) {
try { wallSpools = await api("/spulen"); } catch (error) { /* behalten */ }