From 02449a80deb67d2f368d2ecbd104f19d34433b36 Mon Sep 17 00:00:00 2001 From: nessi Date: Mon, 17 Aug 2026 19:25:30 +0200 Subject: [PATCH] refactor: replace dynamic temperature injection with static rendering in RAID disk template and add I/O pressure panel with PSI metrics Remove DOMContentLoaded script for raid-temperature DOM manipulation with MutationObserver and replace with inline disk.temperature rendering in renderDatastore() RAID devices map. Add #ioPressurePanel CSS with 50% max-width/12px margin/14px padding and io-pressure-bars grid with 42px/48px/1fr columns. Add DOMContentLoaded script to create ioPressurePanel section --- templates/index.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/index.html b/templates/index.html index be1284f..fff550a 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,7 +1,7 @@ - + @@ -132,7 +132,7 @@ const diskList=document.querySelector('#diskList'); function renderSystem(data){const cpu=Number(data.cpu_percent)||0,ram=data.memory||{};const cpuValue=document.querySelector('#cpuValue'),ramValue=document.querySelector('#ramValue'),cpuBar=document.querySelector('#cpuBar'),ramBar=document.querySelector('#ramBar'),updated=document.querySelector('#systemUpdated');if(cpuValue)cpuValue.textContent=`${cpu.toFixed(1)}%`;if(ramValue)ramValue.textContent=`${ram.used||'—'} / ${ram.total||'—'} (${Number(ram.percent||0).toFixed(1)}%)`;if(cpuBar)cpuBar.style.width=`${Math.min(100,cpu)}%`;if(ramBar)ramBar.style.width=`${Math.min(100,Number(ram.percent)||0)}%`;if(updated)updated.textContent='Gerade aktualisiert';if(!diskList)return;diskList.innerHTML=(data.disks||[]).map(d=>`
${html(d.label)}${html(d.path)}
${html(d.used)} / ${html(d.total)}
${Number(d.percent||0).toFixed(1)}% belegt
`).join('')||'
Keine Laufwerke gefunden
'} async function fetchSystem(){try{const response=await fetch('/api/system');renderSystem(await response.json())}catch(error){const updated=document.querySelector('#systemUpdated');if(updated)updated.textContent='Nicht verfügbar'}} if(document.querySelector('#dashboard')){fetchSystem();setInterval(fetchSystem,5000)} -const datastoreView=document.querySelector('#datastore');function renderDatastore(data){const storage=data.storage||{},raid=data.raid||{};const set=(id,value)=>{const node=document.querySelector(id);if(node)node.textContent=value};set('#datastoreTotal',storage.total||'—');set('#datastoreUsed',storage.used||'—');set('#datastoreFree',storage.free||'—');set('#datastorePercent',storage.percent!=null?`${storage.percent}%`:'—');set('#datastorePath',storage.path||'/nesflix');set('#datastoreCapacityLabel',storage.percent!=null?`${storage.used||'—'} / ${storage.total||'—'} · ${storage.percent}%`:storage.error||'Nicht verfügbar');set('#datastoreUpdated',storage.scanned_at?'Gerade aktualisiert':'Nicht verfügbar');const capacityBar=document.querySelector('#datastoreCapacityBar');if(capacityBar)capacityBar.style.width=`${Math.min(100,Number(storage.percent)||0)}%`;const categories=document.querySelector('#datastoreCategories');if(categories){const values=(storage.categories||[]).filter(category=>category.bytes>0||['movies','series','anime','kdrama','downloads'].includes(category.key));categories.innerHTML=values.length?values.map(category=>`
${html(category.label)}${html(category.size||'0 B')}
${Number(category.percent||0).toFixed(1)}% vom belegten Speicher · ${Number(category.files||0).toLocaleString('de-DE')} Dateien
`).join(''):'
Keine Kategorien gefunden
'}const badge=document.querySelector('#raidStatusBadge');if(badge){badge.textContent=raid.label||'UNKNOWN';badge.className=`raid-status ${raid.status||'unknown'}`}set('#raidDevice',raid.device||'/dev/md127');const summary=document.querySelector('#raidSummary');if(summary)summary.innerHTML=`Level${html(raid.level||'—')}Aktiv${html(raid.active_devices??'—')} / ${html(raid.raid_devices??'—')}Fehlend${html(raid.failed_devices??0)}`;const recovery=raid.recovery||{},recoveryBox=document.querySelector('#raidRecovery');if(recoveryBox){recoveryBox.classList.toggle('hidden',!recovery.active);set('#raidRecoveryPercent',`${Number(recovery.percent||0).toFixed(1)}%`);set('#raidRecoverySpeed',recovery.speed||'—');set('#raidRecoveryFinish',recovery.finish||'—');const recoveryBar=document.querySelector('#raidRecoveryBar');if(recoveryBar)recoveryBar.style.width=`${Math.min(100,Number(recovery.percent)||0)}%`}const disks=document.querySelector('#raidDisks');if(disks){disks.innerHTML=(raid.devices||[]).length?(raid.devices||[]).map(disk=>`
${html(disk.device)}Slot ${html(disk.slot||'—')} · ${html(disk.model||'—')}${html(disk.size||'—')} · Seriennummer: ${html(disk.serial||'—')}SMART: ${html(disk.smart||'Nicht aktiviert')}
${html(disk.status||'unknown')}
`).join(''):'
Keine RAID-Mitglieder erkannt
'}if(raid.error){const node=document.querySelector('#raidDisks .datastore-empty');if(node)node.textContent=raid.error}}async function fetchDatastore(){if(!datastoreView)return;try{renderDatastore(await (await fetch('/api/datastore')).json())}catch(error){renderDatastore({storage:{error:'Datastore nicht erreichbar'},raid:{status:'failed',label:'FAILED',error:'RAID-Status nicht verfügbar'}})}}if(datastoreView){fetchDatastore();setInterval(fetchDatastore,5000)} +const datastoreView=document.querySelector('#datastore');function renderDatastore(data){const storage=data.storage||{},raid=data.raid||{};const set=(id,value)=>{const node=document.querySelector(id);if(node)node.textContent=value};set('#datastoreTotal',storage.total||'—');set('#datastoreUsed',storage.used||'—');set('#datastoreFree',storage.free||'—');set('#datastorePercent',storage.percent!=null?`${storage.percent}%`:'—');set('#datastorePath',storage.path||'/nesflix');set('#datastoreCapacityLabel',storage.percent!=null?`${storage.used||'—'} / ${storage.total||'—'} · ${storage.percent}%`:storage.error||'Nicht verfügbar');set('#datastoreUpdated',storage.scanned_at?'Gerade aktualisiert':'Nicht verfügbar');const capacityBar=document.querySelector('#datastoreCapacityBar');if(capacityBar)capacityBar.style.width=`${Math.min(100,Number(storage.percent)||0)}%`;const categories=document.querySelector('#datastoreCategories');if(categories){const values=(storage.categories||[]).filter(category=>category.bytes>0||['movies','series','anime','kdrama','downloads'].includes(category.key));categories.innerHTML=values.length?values.map(category=>`
${html(category.label)}${html(category.size||'0 B')}
${Number(category.percent||0).toFixed(1)}% vom belegten Speicher · ${Number(category.files||0).toLocaleString('de-DE')} Dateien
`).join(''):'
Keine Kategorien gefunden
'}const badge=document.querySelector('#raidStatusBadge');if(badge){badge.textContent=raid.label||'UNKNOWN';badge.className=`raid-status ${raid.status||'unknown'}`}set('#raidDevice',raid.device||'/dev/md127');const summary=document.querySelector('#raidSummary');if(summary)summary.innerHTML=`Level${html(raid.level||'—')}Aktiv${html(raid.active_devices??'—')} / ${html(raid.raid_devices??'—')}Fehlend${html(raid.failed_devices??0)}`;const recovery=raid.recovery||{},recoveryBox=document.querySelector('#raidRecovery');if(recoveryBox){recoveryBox.classList.toggle('hidden',!recovery.active);set('#raidRecoveryPercent',`${Number(recovery.percent||0).toFixed(1)}%`);set('#raidRecoverySpeed',recovery.speed||'—');set('#raidRecoveryFinish',recovery.finish||'—');const recoveryBar=document.querySelector('#raidRecoveryBar');if(recoveryBar)recoveryBar.style.width=`${Math.min(100,Number(recovery.percent)||0)}%`}const disks=document.querySelector('#raidDisks');if(disks){disks.innerHTML=(raid.devices||[]).length?(raid.devices||[]).map(disk=>`
${html(disk.device)}Slot ${html(disk.slot||'—')} · ${html(disk.model||'—')}${html(disk.size||'—')} · Seriennummer: ${html(disk.serial||'—')}SMART: ${html(disk.smart||'Nicht aktiviert')}Temperatur: ${html(disk.temperature||'Nicht verfügbar')}
${html(disk.status||'unknown')}
`).join(''):'
Keine RAID-Mitglieder erkannt
'}if(raid.error){const node=document.querySelector('#raidDisks .datastore-empty');if(node)node.textContent=raid.error}}async function fetchDatastore(){if(!datastoreView)return;try{renderDatastore(await (await fetch('/api/datastore')).json())}catch(error){renderDatastore({storage:{error:'Datastore nicht erreichbar'},raid:{status:'failed',label:'FAILED',error:'RAID-Status nicht verfügbar'}})}}if(datastoreView){fetchDatastore();setInterval(fetchDatastore,5000)}