diff --git a/web/themes/default/app.js b/web/themes/default/app.js index c34e172..781d122 100644 --- a/web/themes/default/app.js +++ b/web/themes/default/app.js @@ -277,8 +277,49 @@ function initPrinters(){ var idx=window._printerIndex||1; _activePrinter=_printers.find(function(p){return String(p.id)===String(idx)})||_printers[0]||null; renderPrinterDropdown(); + _initDashboardPowerCard(); }).catch(function(){}); } + +// ── Dashboard Power Switch (Issue: hard to find + poorly visible in the +// Printers tab; mirrors togglePrinterPower()/_refreshPrinterPowerIcon() for +// the active printer, on a second, more prominent toggle on the Dashboard) ── +function _initDashboardPowerCard(){ + var card=document.getElementById('card-power'); + if(!card)return; + if(!_activePrinter||!_activePrinter.has_power_control){card.style.display='none';return;} + card.style.display=''; + _refreshDashboardPower(); +} +function _refreshDashboardPower(){ + if(!_activePrinter||!_activePrinter.has_power_control)return; + var bridgeUrl=(_activePrinter.bridge_url||'').replace(/\/+$/,''); + fetch(bridgeUrl+'/kx/printers/'+encodeURIComponent(_activePrinter.id)+'/power-status',{signal:AbortSignal.timeout(5000)}) + .then(function(r){return r.json()}) + .then(function(d){ + var onBtn=document.getElementById('d-power-on'), offBtn=document.getElementById('d-power-off'); + if(!onBtn||!offBtn)return; + onBtn.classList.toggle('spd-active',d.state==='on'); + offBtn.classList.toggle('spd-active',d.state==='off'); + }) + .catch(function(){/* status endpoint optional - toggle just stays neutral */}); +} +function setDashboardPower(action){ + if(!_activePrinter)return; + if(action==='off'&&!confirm(T.printers_power_off_confirm||'Turn printer power off? Make sure no print is running.'))return; + var onBtn=document.getElementById('d-power-on'), offBtn=document.getElementById('d-power-off'); + if(onBtn)onBtn.style.opacity='0.5'; + if(offBtn)offBtn.style.opacity='0.5'; + post('/kx/printers/'+encodeURIComponent(_activePrinter.id)+'/power',{action:action}).then(function(){ + if(onBtn)onBtn.style.opacity='1'; + if(offBtn)offBtn.style.opacity='1'; + setTimeout(_refreshDashboardPower,1500); + }).catch(function(e){ + if(onBtn)onBtn.style.opacity='1'; + if(offBtn)offBtn.style.opacity='1'; + clog('Power-Fehler: '+e,'msg-err'); + }); +} function renderPrinterDropdown(){ var wrap=document.getElementById('printer-dropdown-wrap'); var single=document.getElementById('h-pname-single'); @@ -367,6 +408,9 @@ function applyLang(){ setText('d-card-temps',T.card_temps); setText('d-card-lightfan',T.card_light_fan); setText('d-card-speed',T.card_speed); + setText('d-card-power',T.card_power); + setText('d-power-lbl-on',T.printers_power_on_short||'An'); + setText('d-power-lbl-off',T.printers_power_off_short||'Aus'); setText('d-card-cam',T.card_cam); setText('d-card-ams',T.panel_ams_title); setText('d-lbl-elapsed',T.lbl_elapsed); @@ -2025,6 +2069,7 @@ var pollTimer; }).catch(function(){}); poll();pollTimer=setInterval(poll,ms); setInterval(_loadSpoolmanStatus,30000); + setInterval(_refreshDashboardPower,30000); // initDashGrid() is called at the very end of the file, after all the // DASH_* var declarations below have executed (they are hoisted but not yet // assigned at this point in the IIFE). @@ -2041,7 +2086,7 @@ var pollTimer; // - columnOpts.breakpoints -> 1-column below 700px GRID width (sidebar-aware) var DASH_STORAGE_KEY='dashLayout'; var DASH_LAYOUT_VERSION=3; // v1/v2 = older editors; discard those states -var DASH_CARD_KEYS=['camera','progress','temps','motion','speed','fan','ams']; +var DASH_CARD_KEYS=['camera','progress','temps','motion','speed','power','fan','ams']; // Layout arrays in GridStack save()/load() format. cellHeight=60px. var DASH_DEFAULT_LAYOUT=[ {id:'camera', x:0,y:0, w:12,h:7}, @@ -2049,8 +2094,9 @@ var DASH_DEFAULT_LAYOUT=[ {id:'temps', x:0,y:13,w:6, h:7}, {id:'motion', x:6,y:13,w:6, h:7}, {id:'speed', x:0,y:20,w:6, h:3}, - {id:'fan', x:6,y:20,w:6, h:3}, - {id:'ams', x:0,y:23,w:12,h:4}, + {id:'power', x:6,y:20,w:6, h:3}, + {id:'fan', x:0,y:23,w:6, h:3}, + {id:'ams', x:0,y:26,w:12,h:4}, ]; // "Wide desktop" preset (Blaim, Issue #89): big camera left, settings center, // motion right. @@ -2128,6 +2174,20 @@ function initDashGrid(){ var item=_dashItem(n.id); if(item){_dashGrid.removeWidget(item,false);item.style.display='none';} }); + // Cards added after a user's layout was already saved (e.g. the "power" + // card) never appear otherwise: load(...,false) only updates ids already + // present in the saved layout, it never adds new ones. Append any missing + // known card next to its default-layout neighbour instead of silently + // dropping it - the alternative (bumping DASH_LAYOUT_VERSION) would wipe + // every user's custom layout just to surface one new card. + var known={}; + state.layout.forEach(function(n){known[n.id]=true;}); + _dashHidden.forEach(function(n){known[n.id]=true;}); + DASH_DEFAULT_LAYOUT.forEach(function(def){ + if(known[def.id])return; + var item=_dashItem(def.id); + if(item)_dashGrid.addWidget(item,{x:def.x,y:def.y,w:def.w,h:def.h}); + }); }else{ _dashGrid.load(DASH_DEFAULT_LAYOUT,false); } diff --git a/web/themes/default/index.html b/web/themes/default/index.html index c12fe1d..2c1c5e4 100644 --- a/web/themes/default/index.html +++ b/web/themes/default/index.html @@ -335,6 +335,21 @@ + +
+