Files
design-v3/source/pages/04-printers.html
T

210 lines
18 KiB
HTML
Raw Normal View History

2026-09-19 11:31:50 -04:00
<style>
.datasrc { padding: var(--space-4) var(--space-5); display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-4); align-items: center; }
.group-h { display: flex; align-items: center; gap: var(--space-3); margin: 0 0 var(--space-4); font-size: var(--fs-label); text-transform: uppercase; letter-spacing: var(--tracking-caps-wide); color: var(--text-secondary); font-weight: var(--fw-bold); }
.group-h .n { display: inline-grid; place-items: center; min-width: 24px; height: 24px; border-radius: var(--radius-pill); background: var(--surface-inset); box-shadow: var(--nm-inset-1); border: 1px solid var(--border-hairline); color: var(--text-primary); }
.groups { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); gap: var(--space-6); align-items: start; }
.pgrid { display: grid; gap: var(--space-6); }
.pcard { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-4); }
.pcard.attn { border: 2px solid var(--status-warning); }
.phead { display: flex; gap: var(--space-3); align-items: flex-start; }
.phead h3 { margin: 0; font-size: var(--fs-h3); line-height: var(--lh-snug); }
.phead .model { font-size: var(--fs-label); color: var(--text-secondary); }
.cam { aspect-ratio: 16 / 9; border-radius: var(--radius-md); background: radial-gradient(ellipse at 50% 90%, #5a4b3a 0 28%, transparent 29%), linear-gradient(180deg, #1c1d22 0%, #2b2c33 60%, #3a3326 100%); border: 1px solid var(--border-control); box-shadow: var(--nm-inset-2); position: relative; overflow: hidden; }
.cam::after { content: ""; position: absolute; left: 30%; right: 30%; bottom: 20%; height: 22%; background: repeating-linear-gradient(0deg, #6b8fd6 0 3px, #5a7cc2 3px 6px); border-radius: 4px 4px 0 0; opacity: .85; }
.cam .stamp { position: absolute; left: 10px; top: 8px; font-size: var(--fs-caption); color: #f4f4f6; background: rgba(0, 0, 0, .55); padding: 2px 8px; border-radius: var(--radius-pill); z-index: 1; }
.cam-off { min-height: 72px; border-radius: var(--radius-md); border: 1px dashed var(--border-control); display: grid; place-items: center; text-align: center; padding: var(--space-4); color: var(--text-secondary); font-size: var(--fs-label); }
.nowjob { padding: var(--space-4); display: grid; grid-template-columns: 1fr auto; gap: 2px var(--space-3); }
.nowjob .jn { font-weight: var(--fw-bold); }
.slots4 { display: grid; gap: var(--space-2); }
.cont { padding: var(--space-3) var(--space-4); }
.cont-h { display: flex; justify-content: space-between; font-size: var(--fs-label); margin-bottom: var(--space-2); }
.slotrow { display: grid; grid-template-columns: 22px auto minmax(0, 1fr) auto; gap: var(--space-2) var(--space-3); align-items: center; font-size: 13px; padding: 4px 0; }
.slotrow .i { color: var(--text-secondary); font-size: var(--fs-caption); }
.slotrow.empty .nm { color: var(--text-secondary); font-style: italic; }
.conn { display: grid; grid-template-columns: auto 1fr; gap: 4px var(--space-4); font-size: var(--fs-label); margin: 0; }
.conn dt { color: var(--text-secondary); }
.conn dd { margin: 0; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
details.cfg { border-top: 1px solid var(--border-hairline); padding-top: var(--space-3); }
details.cfg summary { cursor: pointer; font-size: var(--fs-label); font-weight: var(--fw-bold); }
details.cfg summary:focus-visible { outline: var(--focus-width) solid var(--focus-ring); outline-offset: 2px; border-radius: 4px; }
.lost { padding: var(--space-4); border-radius: var(--radius-md); border: 1px solid var(--status-warning); background: var(--wash-warning); display: flex; flex-direction: column; gap: var(--space-2); font-size: 13px; }
.lost h4 { margin: 0; color: var(--status-warning); font-size: 14px; }
.lost ul { margin: 0; padding-left: 18px; }
.stale { opacity: 1; border-style: dashed !important; }
.stale-tag { font-size: var(--fs-caption); color: var(--status-warning); font-weight: var(--fw-bold); }
.pulse { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--status-success); box-shadow: 0 0 0 3px var(--wash-success); }
.future { padding: var(--space-6); border: 2px dashed var(--border-control); border-radius: var(--radius-lg); background: transparent; }
.future h2 { margin: 0; font-size: var(--fs-h3); display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; }
.fgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--space-4); margin-top: var(--space-5); }
.fitem { padding: var(--space-4); border: 1px dashed var(--border-control); border-radius: var(--radius-md); display: flex; flex-direction: column; gap: var(--space-2); }
.fitem h3 { margin: 0; font-size: 14px; }
.fitem .why { font-size: var(--fs-caption); color: var(--text-secondary); line-height: var(--lh-snug); }
.ghost { opacity: .9; filter: grayscale(1); pointer-events: none; }
body.dev-only [data-feature] { display: none !important; }
body:not(.dev-only) [data-devonly] { display: none !important; }
</style>
<header class="page-head">
<div>
<h1>Printers</h1>
<p class="muted">3 printers · status polled every 10 s · MQTT is read-only</p>
</div>
<div class="actions">
<button class="btn" type="button">Manage AMS units</button>
<button class="btn btn-primary" type="button">+ Add printer</button>
</div>
</header>
<section class="datasrc nm-raised" aria-label="Data source">
<span class="small"><b>Data shown</b></span>
<div class="seg" role="group" aria-label="Which build's data to show" id="ds">
<button type="button" data-ds="dev" aria-pressed="false">dev today</button>
<button type="button" data-ds="feat" aria-pressed="true">dev + printer-connections branch</button>
</div>
<span class="small muted">Fields tagged <span class="chip chip-info chip-dashed">feature</span> exist only on <code>feature/7efc2030…-printer-connections</code> (4e17f9e), not in production.</span>
</section>
<div class="groups">
<section aria-labelledby="g-progress">
<h2 class="group-h" id="g-progress">In progress <span class="n">1</span></h2>
<div class="pgrid">
<article class="pcard nm-raised" aria-labelledby="p1">
<div class="phead">
<div style="flex:1;min-width:0"><h3 id="p1">P1S - Prints Charming</h3><span class="model">Bambu Lab · P1S</span></div>
<span class="chip chip-accent">● Printing</span>
<button class="btn btn-icon btn-sm" type="button" aria-label="Actions for P1S - Prints Charming" aria-haspopup="menu">⋯</button>
</div>
<div class="row small" data-feature><span class="pulse" aria-hidden="true"></span><span>Ready · last report <b>2s ago</b></span><span class="chip chip-info chip-dashed">feature</span></div>
<div class="row small" data-devonly><span class="pulse" aria-hidden="true"></span><span>Connected</span></div>
<div class="cam" role="img" aria-label="Camera snapshot from P1S - Prints Charming"><span class="stamp">snapshot 09:41:02</span></div>
<div class="nowjob nm-inset">
<span class="jn">Gridfinity_bins_3x2</span><span class="num">1h 04m</span>
<span class="small muted">started 08:37 · weight read from the 3MF when it ends</span><span class="small muted">so far</span>
</div>
<div class="slots4" aria-label="Filament loaded in P1S - Prints Charming">
<div class="row"><span class="small"><b>Loaded filament</b></span><span class="chip chip-neutral">not confirmed in use</span></div>
<div class="cont nm-inset">
<div class="cont-h"><b>AMS 1</b><span class="muted">4 / 4</span></div>
<div class="slotrow"><span class="i">1</span><span class="swatch swatch-sm"><i style="background:#141414"></i></span><span class="nm">Sunlu · Black <span class="muted">PLA + 2.0</span></span><span class="num">1000 g</span></div>
<div class="slotrow"><span class="i">2</span><span class="swatch swatch-sm"><i style="background:#b87333"></i></span><span class="nm">Sunlu · Copper <span class="muted">PLA + Silk</span></span><span class="num" style="color:var(--status-warning)">⚠ 97 g</span></div>
<div class="slotrow"><span class="i">3</span><span class="swatch swatch-sm"><i style="background:#ece8df"></i></span><span class="nm">Overture · Mist Gray <span class="muted">PLA Marble</span></span><span class="num">920 g</span></div>
<div class="slotrow"><span class="i">4</span><span class="swatch swatch-sm"><i style="background:#101010"></i></span><span class="nm">JAYO · Black <span class="muted">Rapid PETG Matte</span></span><span class="num">655 g</span></div>
</div>
<div class="cont nm-inset">
<div class="cont-h"><b>External</b><span class="muted">0 / 1</span></div>
<div class="slotrow empty"><span class="i">1</span><span></span><span class="nm">Empty</span><span></span></div>
</div>
</div>
<details class="cfg"><summary>Connection details (stored)</summary>
<dl class="conn" style="margin-top:8px">
<dt>IP</dt><dd>10.60.1.242</dd><dt>Serial</dt><dd>01P09A••••••4821</dd><dt>Access code</dt><dd>✓ stored, never shown</dd><dt>Added</dt><dd>7 Aug 2026</dd>
<dt data-feature>Session</dt><dd data-feature>#3 <span class="chip chip-info chip-dashed">feature</span></dd>
</dl></details>
<p class="small muted" style="margin:0">Last finished: Lid_v3 · failed yesterday 16:49</p>
</article>
</div>
</section>
<section aria-labelledby="g-attn">
<h2 class="group-h" id="g-attn">Needs attention <span class="n">1</span></h2>
<div class="pgrid">
<article class="pcard nm-raised attn" aria-labelledby="p3">
<div class="phead">
<div style="flex:1;min-width:0"><h3 id="p3">A1 - Jordyns Layer Slayer</h3><span class="model">Bambu Lab · A1</span></div>
<span class="chip chip-warn" data-feature>⟳ Reconnecting</span>
<span class="chip chip-warn" data-devonly>⚡ Offline</span>
<button class="btn btn-icon btn-sm" type="button" aria-label="Actions for A1 - Jordyns Layer Slayer" aria-haspopup="menu">⋯</button>
</div>
<div class="lost" role="status">
<h4>⚡ MQTT connection lost</h4>
<span data-feature>Disconnected, reconnecting. Last contact <b>6m ago</b> (09:35:11). <span class="chip chip-info chip-dashed">feature</span></span>
<span data-devonly>Extrudex's MQTT session to this printer dropped. The time it dropped isn't recorded on dev.</span>
<ul class="small">
<li>The printer itself may still be printing. This is Extrudex's connection, not the printer's power.</li>
<li><b>Print capture is paused.</b> A job that starts and finishes during the outage won't be recorded.</li>
<li>On reconnect: if <i>Coaster_set</i> is still running, its record stays open and gets <b>+1 gap</b> (its duration becomes an upper bound). Otherwise it closes as <b>unknown</b>, with no duration.</li>
</ul>
</div>
<div class="nowjob nm-inset stale" style="border:1px dashed var(--status-warning)">
<span class="jn">Coaster_set</span><span class="stale-tag">OPEN RECORD</span>
<span class="small muted">started 08:55 · watched until the connection dropped</span><span></span>
<span class="small" data-feature style="grid-column:1/-1"><span class="stale-tag">Last known:</span> Printing · 6m ago. Cached from the lost session, not live. <span class="chip chip-info chip-dashed">feature</span></span>
</div>
<div class="cam-off">Camera unavailable while the printer is offline</div>
<div class="slots4" aria-label="Filament loaded in A1 - Jordyns Layer Slayer">
<div class="row"><span class="small"><b>Loaded filament</b></span><span class="chip chip-neutral">from Extrudex records, not the printer</span></div>
<div class="cont nm-inset">
<div class="cont-h"><b>AMS Lite</b><span class="muted">2 / 4</span></div>
<div class="slotrow"><span class="i">1</span><span class="swatch swatch-sm"><i style="background:#1b1b1b"></i></span><span class="nm">Sunlu · Black <span class="muted">PETG CF Matte</span></span><span class="num">812 g</span></div>
<div class="slotrow"><span class="i">2</span><span class="swatch swatch-sm"><i style="background:#e8453c"></i><i style="background:#f2c230"></i><i style="background:#2a8fd6"></i></span><span class="nm">AMOLEN · Red Yellow Blue <span class="muted">PLA Matte</span></span><span class="num">744 g</span></div>
<div class="slotrow empty"><span class="i">3</span><span></span><span class="nm">Empty</span><span></span></div>
<div class="slotrow empty"><span class="i">4</span><span></span><span class="nm">Empty</span><span></span></div>
</div>
</div>
<details class="cfg" open><summary>Connection details (stored)</summary>
<dl class="conn" style="margin-top:8px">
<dt>IP</dt><dd>10.60.1.x <span class="muted">(sample)</span></dd><dt>Serial</dt><dd>039••••••••7710</dd><dt>Access code</dt><dd>✓ stored, never shown</dd>
<dt data-feature>Lifecycle</dt><dd data-feature>reconnecting · <code>stale: true</code> <span class="chip chip-info chip-dashed">feature</span></dd>
<dt data-feature>Failure</dt><dd data-feature><span class="muted">none reported. A reconnect can have no failure detail.</span></dd>
<dt data-feature>Session</dt><dd data-feature>#14 (increments on every reconnect)</dd>
</dl></details>
<div class="actions"><button class="btn btn-sm" type="button">Edit connection</button><span class="small muted">Retrying automatically. There's nothing to press.</span></div>
</article>
</div>
</section>
<section aria-labelledby="g-idle">
<h2 class="group-h" id="g-idle">Idle <span class="n">1</span></h2>
<div class="pgrid">
<article class="pcard nm-raised-sm" aria-labelledby="p2" style="padding: var(--space-5)">
<div class="phead">
<div style="flex:1;min-width:0"><h3 id="p2">H2C - Constipation Orion</h3><span class="model">Bambu Lab · H2C</span></div>
<span class="chip chip-neutral">Idle</span>
<button class="btn btn-icon btn-sm" type="button" aria-label="Actions for H2C - Constipation Orion" aria-haspopup="menu">⋯</button>
</div>
<div class="row small"><span class="pulse" aria-hidden="true"></span><span data-feature>Ready · last report 4s ago <span class="chip chip-info chip-dashed">feature</span></span><span data-devonly>Connected</span></div>
<p class="small" style="margin:0">Last: <b>Benchy_x4</b> · finished 05:27 · <span style="color:var(--status-warning);font-weight:700">≤ 3h 12m</span> <span class="chip chip-warn chip-dashed">upper bound · 1 gap</span></p>
<div class="cont nm-inset">
<div class="cont-h"><b>AMS 1</b><span class="muted">3 / 4</span></div>
<div class="slotrow"><span class="i">1</span><span class="swatch swatch-sm"><i style="background:#141414"></i></span><span class="nm">Elegoo · Black <span class="muted">Rapid PETG</span></span><span class="num" style="color:var(--status-warning)">⚠ 142 g</span></div>
<div class="slotrow"><span class="i">2</span><span class="swatch swatch-sm"><i style="background:#1d4fa8"></i></span><span class="nm">Elegoo · Blue <span class="muted">Rapid PETG</span></span><span class="num">1000 g</span></div>
<div class="slotrow"><span class="i">3</span><span class="swatch swatch-sm"><i style="background:#f4f4f0"></i></span><span class="nm">Elegoo · White <span class="muted">PLA Matte</span></span><span class="num">610 g</span></div>
<div class="slotrow empty"><span class="i">4</span><span></span><span class="nm">Empty</span><span></span></div>
</div>
<details class="cfg"><summary>Connection details (stored)</summary>
<dl class="conn" style="margin-top:8px"><dt>IP</dt><dd>10.60.1.202</dd><dt>Serial</dt><dd>31B••••••••0093</dd><dt>Access code</dt><dd>✓ stored, never shown</dd></dl></details>
</article>
</div>
</section>
</div>
<section class="future" aria-labelledby="future-h">
<h2 id="future-h"><span class="chip chip-neutral chip-dashed">Future, not built</span> Ideas that need data Extrudex doesn't store</h2>
<p class="small muted" style="margin:var(--space-2) 0 0">Nothing in this box can be built from today's data. Each item says what's missing.</p>
<div class="fgrid">
<div class="fitem"><h3>Progress % and time left</h3><div class="track ghost" aria-hidden="true"><span style="width:58%"></span></div>
<span class="why"><code>mc_percent</code> is parsed from MQTT but used only internally. It isn't stored or returned by <code>/api/printers</code>. ETA isn't read at all.</span></div>
<div class="fitem"><h3>Nozzle and bed temperature</h3><span class="ghost small">220 °C · 60 °C</span>
<span class="why">Temperatures aren't parsed from the report.</span></div>
<div class="fitem"><h3>Current layer</h3><span class="ghost small">Layer 112 / 190</span>
<span class="why">Layer fields aren't parsed.</span></div>
<div class="fitem"><h3>AMS remaining % and humidity</h3><span class="ghost small">82% · humidity 2</span>
<span class="why">Not read. AMS <code>remain</code> is only meaningful for genuine RFID spools, which isn't what's mostly run here.</span></div>
<div class="fitem"><h3>Alert when MQTT drops</h3><span class="ghost small">🔔 notify after 5 min</span>
<span class="why">Drops only show in container logs today (CONTEXT open work #4). On dev, nothing stores <i>when</i> it dropped.</span></div>
<div class="fitem"><h3>Which spool is feeding now</h3><span class="ghost small">▶ AMS 1 · slot 2</span>
<span class="why">"Loaded" is recorded; "in use" isn't. That's why the list says <i>not confirmed in use</i>.</span></div>
</div>
</section>
<script>
(function(){
function set(v){document.body.classList.toggle('dev-only', v==='dev');
document.querySelectorAll('#ds [data-ds]').forEach(function(b){b.setAttribute('aria-pressed',String(b.getAttribute('data-ds')===v))});}
document.addEventListener('click',function(e){var b=e.target.closest('#ds [data-ds]'); if(b) set(b.getAttribute('data-ds'));});
})();
</script>