diff --git a/webapp/templates/imaging.html b/webapp/templates/imaging.html
index 9162af1..d5a6a31 100644
--- a/webapp/templates/imaging.html
+++ b/webapp/templates/imaging.html
@@ -96,6 +96,23 @@
{% endif %}
+ {% if s.intune_device_id %}
+
+ LAPS password QR (paste -> scan on bay)
+
+
+
+
+
+
+
+
+ {% endif %}
+
{% if s.log_tail %}
Log tail ({{ s.log_tail | length }} line{{ 's' if s.log_tail | length != 1 }})
@@ -202,5 +219,67 @@ document.addEventListener('click', function(e) {
copyText(text).then(function() { flashCopied(btn, true); })
.catch(function(err) { console.error('copy failed:', err); flashCopied(btn, false); });
});
+
+// LAPS password -> client-side QR. Password never leaves browser tab.
+// Auto-clears input + QR after 60s so it doesn't linger on shared screens.
+function renderLapsQR(card) {
+ var input = card.querySelector('.laps-input');
+ var container = card.querySelector('.laps-qr-container');
+ var makeBtn = card.querySelector('.laps-make-btn');
+ var clearBtn = card.querySelector('.laps-clear-btn');
+ var timerEl = card.querySelector('.laps-timer');
+ var text = input.value;
+ if (!text) { input.focus(); return; }
+ try {
+ var qr = qrcode(0, 'M');
+ qr.addData(text);
+ qr.make();
+ var modules = qr.getModuleCount();
+ var size = 280;
+ var cellSize = Math.max(1, Math.floor(size / (modules + 8)));
+ container.innerHTML = qr.createImgTag(cellSize, 4);
+ makeBtn.style.display = 'none';
+ clearBtn.style.display = '';
+ var remaining = 60;
+ timerEl.textContent = '(auto-clears in ' + remaining + 's)';
+ if (card._lapsTimer) clearInterval(card._lapsTimer);
+ card._lapsTimer = setInterval(function() {
+ remaining--;
+ if (remaining <= 0) { clearLapsQR(card); return; }
+ timerEl.textContent = '(auto-clears in ' + remaining + 's)';
+ }, 1000);
+ } catch (err) {
+ container.textContent = 'QR error: ' + err;
+ }
+}
+function clearLapsQR(card) {
+ var input = card.querySelector('.laps-input');
+ var container = card.querySelector('.laps-qr-container');
+ var makeBtn = card.querySelector('.laps-make-btn');
+ var clearBtn = card.querySelector('.laps-clear-btn');
+ var timerEl = card.querySelector('.laps-timer');
+ if (card._lapsTimer) { clearInterval(card._lapsTimer); card._lapsTimer = null; }
+ input.value = '';
+ container.innerHTML = '';
+ timerEl.textContent = '';
+ makeBtn.style.display = '';
+ clearBtn.style.display = 'none';
+}
+document.addEventListener('click', function(e) {
+ var card;
+ if (e.target.classList.contains('laps-make-btn')) {
+ card = e.target.closest('.laps-card');
+ if (card) renderLapsQR(card);
+ } else if (e.target.classList.contains('laps-clear-btn')) {
+ card = e.target.closest('.laps-card');
+ if (card) clearLapsQR(card);
+ }
+});
+document.addEventListener('keydown', function(e) {
+ if (e.key === 'Enter' && e.target.classList.contains('laps-input')) {
+ var card = e.target.closest('.laps-card');
+ if (card) { e.preventDefault(); renderLapsQR(card); }
+ }
+});
{% endblock %}