feat: Verbesserung der Speicherinformationen-Funktion zur besseren Unterscheidung von Quell- und Zielgeräten; Versionsnummer auf 1.0.70 erhöht
This commit is contained in:
116
app.py
116
app.py
@@ -1534,43 +1534,47 @@ def r_storage_info():
|
||||
devs = usb_devices()
|
||||
result = []
|
||||
|
||||
src_ports = {sp['port'] for sp in _resolve_source_ports(cfg)}
|
||||
dst_port = cfg.get('dest_port')
|
||||
|
||||
def _du_for_dev(dev):
|
||||
mp, owned = ensure_mount(dev)
|
||||
if not mp:
|
||||
return dict(mounted=False, total=None, used=None, free=None, pct=None)
|
||||
return dict(total=None, used=None, free=None, pct=None)
|
||||
try:
|
||||
du = shutil.disk_usage(mp)
|
||||
return dict(mounted=True, total=du.total, used=du.used, free=du.free,
|
||||
return dict(total=du.total, used=du.used, free=du.free,
|
||||
pct=round(du.used / du.total * 100) if du.total else 0)
|
||||
except Exception:
|
||||
return dict(mounted=False, total=None, used=None, free=None, pct=None)
|
||||
return dict(total=None, used=None, free=None, pct=None)
|
||||
finally:
|
||||
if owned:
|
||||
subprocess.run(['umount', mp], capture_output=True)
|
||||
|
||||
for sp in _resolve_source_ports(cfg):
|
||||
dev = next((d for d in devs if d['usb_port'] == sp['port']), None)
|
||||
entry = dict(type='source', label=sp.get('label') or f"Port {sp['port']}",
|
||||
port=sp['port'], mounted=False,
|
||||
total=None, used=None, free=None, pct=None)
|
||||
if dev:
|
||||
entry.update(_du_for_dev(dev))
|
||||
for dev in devs:
|
||||
port = dev['usb_port']
|
||||
if port in src_ports:
|
||||
role = 'source'
|
||||
elif port == dst_port:
|
||||
role = 'dest'
|
||||
else:
|
||||
role = 'other'
|
||||
entry = dict(
|
||||
role=role,
|
||||
label=dev.get('label') or dev.get('device') or f'Port {port}',
|
||||
port=port,
|
||||
device=dev.get('device', ''),
|
||||
size_str=dev.get('size', ''),
|
||||
)
|
||||
entry.update(_du_for_dev(dev))
|
||||
result.append(entry)
|
||||
|
||||
if cfg.get('dest_type') == 'internal':
|
||||
entry = dict(type='dest',
|
||||
entry = dict(role='dest',
|
||||
label=cfg.get('internal_dest_label') or 'Interner Speicher',
|
||||
port='__internal__')
|
||||
port='__internal__', device='internal', size_str='')
|
||||
entry.update(_du_for_dev({'internal': True}))
|
||||
result.append(entry)
|
||||
elif cfg.get('dest_port'):
|
||||
dev = next((d for d in devs if d['usb_port'] == cfg['dest_port']), None)
|
||||
entry = dict(type='dest', label=cfg.get('dest_label') or f"Port {cfg['dest_port']}",
|
||||
port=cfg['dest_port'], mounted=False,
|
||||
total=None, used=None, free=None, pct=None)
|
||||
if dev:
|
||||
entry.update(_du_for_dev(dev))
|
||||
result.append(entry)
|
||||
|
||||
return jsonify(result)
|
||||
|
||||
@@ -2503,8 +2507,7 @@ body{background:var(--bg);color:var(--txt);font-family:-apple-system,BlinkMacSys
|
||||
<div class="card-head">
|
||||
<div class="card-icon green">⇄</div>
|
||||
<span class="card-title">USB Ports & Datei-Explorer</span>
|
||||
<button class="btn sm ghost" style="margin-left:auto" onclick="toggleStoragePanel()">💾 Speicher</button>
|
||||
<button class="btn sm ghost danger" style="margin-left:.4rem" onclick="resetPorts()">↻ Ports zurücksetzen</button>
|
||||
<button class="btn sm ghost danger" style="margin-left:auto" onclick="resetPorts()">↻ Ports zurücksetzen</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="pex-grid">
|
||||
@@ -2618,17 +2621,6 @@ body{background:var(--bg);color:var(--txt);font-family:-apple-system,BlinkMacSys
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Speicher-Panel -->
|
||||
<div id="storage-panel" style="display:none;margin-top:.85rem;padding:.75rem;background:var(--bg2);border:1px solid var(--brd);border-radius:var(--r)">
|
||||
<div style="display:flex;align-items:center;gap:.5rem;margin-bottom:.65rem">
|
||||
<span style="font-size:.82rem;font-weight:700;color:var(--txt)">💾 Speicherübersicht</span>
|
||||
<button class="btn sm ghost" style="margin-left:auto" onclick="loadStorageInfo()">↻ Aktualisieren</button>
|
||||
</div>
|
||||
<div id="storage-list" style="display:flex;flex-direction:column;gap:.55rem">
|
||||
<div style="color:var(--sub);font-size:.82rem">Wird geladen…</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Nicht zugewiesene Geräte -->
|
||||
<div id="unassigned-wrap" style="display:none;margin-top:.85rem">
|
||||
<div class="sec">Weitere verbundene Geräte</div>
|
||||
@@ -2901,6 +2893,7 @@ body{background:var(--bg);color:var(--txt);font-family:-apple-system,BlinkMacSys
|
||||
<div class="si-bar"><div class="si-fill ok" id="si-disk-bar" style="width:0%"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="storage-list" style="display:flex;flex-direction:column;gap:.4rem"></div>
|
||||
<button class="btn" style="width:100%" onclick="checkUpdate()">🔍 Nach Update suchen</button>
|
||||
<div id="sys-update-flash" class="flash" style="display:none"></div>
|
||||
<button class="btn" style="width:100%;background:rgba(220,60,60,.12);color:#e05555;border-color:rgba(220,60,60,.25)" onclick="rebootDevice()">↺ Gerät neu starten</button>
|
||||
@@ -3874,60 +3867,47 @@ async function pollSysinfo(){
|
||||
db.className='si-fill '+(s.disk_pct>=90?'hot':s.disk_pct>=75?'warn':'ok');
|
||||
}
|
||||
}catch(e){}
|
||||
loadStorageInfo();
|
||||
}
|
||||
|
||||
// -- Speicher-Panel -----------------------------------------------------------
|
||||
function fmtBytes(b){
|
||||
if(b==null) return '–';
|
||||
if(b<1024**3) return (b/1024**2).toFixed(1)+' MB';
|
||||
return (b/1024**3).toFixed(2)+' GB';
|
||||
}
|
||||
let storagePanelOpen=false;
|
||||
function toggleStoragePanel(){
|
||||
storagePanelOpen=!storagePanelOpen;
|
||||
const p=$('storage-panel');
|
||||
p.style.display=storagePanelOpen?'block':'none';
|
||||
if(storagePanelOpen) loadStorageInfo();
|
||||
}
|
||||
// -- Speicher (System-Karte) --------------------------------------------------
|
||||
async function loadStorageInfo(){
|
||||
const list=$('storage-list');
|
||||
list.innerHTML='<div style="color:var(--sub);font-size:.82rem">Wird geladen…</div>';
|
||||
if(!list) return;
|
||||
try{
|
||||
const items=await api('/storage-info');
|
||||
if(!items||!items.length){
|
||||
list.innerHTML='<div style="color:var(--sub);font-size:.82rem">Keine Geräte konfiguriert.</div>';
|
||||
return;
|
||||
}
|
||||
if(!items||!items.length){ list.innerHTML=''; return; }
|
||||
list.innerHTML=items.map(it=>{
|
||||
const icon=it.type==='source'?'▲':'▼';
|
||||
const typeLabel=it.type==='source'?'Quelle':'Ziel';
|
||||
const color=it.type==='source'?'var(--grn)':'var(--acc)';
|
||||
if(!it.mounted||it.total==null){
|
||||
return `<div style="display:flex;align-items:center;gap:.55rem;padding:.4rem .5rem;background:var(--surf);border:1px solid var(--brd);border-radius:.4rem">
|
||||
<span style="font-size:.8rem;color:${color}">${icon}</span>
|
||||
const roleColor=it.role==='source'?'var(--grn)':it.role==='dest'?'var(--acc)':'var(--sub)';
|
||||
const roleIcon=it.role==='source'?'▲':it.role==='dest'?'▼':'■';
|
||||
const roleLabel=it.role==='source'?'Quelle':it.role==='dest'?'Ziel':'Gerät';
|
||||
const portStr=it.port==='__internal__'?'intern':'Port '+it.port;
|
||||
if(it.total==null){
|
||||
const fallback=it.size_str?it.size_str:'–';
|
||||
return `<div style="display:flex;align-items:center;gap:.5rem;padding:.35rem .45rem;background:var(--bg2);border:1px solid var(--brd);border-radius:.4rem">
|
||||
<span style="font-size:.78rem;color:${roleColor};flex-shrink:0">${roleIcon}</span>
|
||||
<div style="min-width:0;flex:1">
|
||||
<div style="font-size:.79rem;font-weight:600;color:var(--txt)">${it.label}</div>
|
||||
<div style="font-size:.73rem;color:var(--sub)">${typeLabel} · Port ${it.port==='__internal__'?'intern':it.port} · nicht verbunden</div>
|
||||
<div style="font-size:.78rem;font-weight:600;color:var(--txt);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${it.label}</div>
|
||||
<div style="font-size:.71rem;color:var(--sub)">${roleLabel} · ${portStr} · ${fallback}</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
const pct=it.pct||0;
|
||||
const barCls=pct>=90?'hot':pct>=75?'warn':'ok';
|
||||
return `<div style="padding:.45rem .5rem;background:var(--surf);border:1px solid var(--brd);border-radius:.4rem">
|
||||
<div style="display:flex;align-items:center;gap:.55rem;margin-bottom:.35rem">
|
||||
<span style="font-size:.8rem;color:${color}">${icon}</span>
|
||||
const barColor=barCls==='hot'?'var(--red)':barCls==='warn'?'var(--ylw)':'var(--grn)';
|
||||
return `<div style="padding:.35rem .45rem;background:var(--bg2);border:1px solid var(--brd);border-radius:.4rem">
|
||||
<div style="display:flex;align-items:center;gap:.5rem;margin-bottom:.3rem">
|
||||
<span style="font-size:.78rem;color:${roleColor};flex-shrink:0">${roleIcon}</span>
|
||||
<div style="min-width:0;flex:1">
|
||||
<div style="font-size:.79rem;font-weight:600;color:var(--txt)">${it.label}</div>
|
||||
<div style="font-size:.73rem;color:var(--sub)">${typeLabel} · ${fmtBytes(it.used)} belegt · ${fmtBytes(it.free)} frei · ${fmtBytes(it.total)} gesamt</div>
|
||||
<div style="font-size:.78rem;font-weight:600;color:var(--txt);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${it.label}</div>
|
||||
<div style="font-size:.71rem;color:var(--sub)">${roleLabel} · ${portStr} · ${fmtBytes(it.used)} / ${fmtBytes(it.total)} · ${fmtBytes(it.free)} frei</div>
|
||||
</div>
|
||||
<span style="font-size:.76rem;font-weight:700;color:var(--${barCls==='hot'?'red':barCls==='warn'?'ylw':'grn'});flex-shrink:0">${pct}%</span>
|
||||
<span style="font-size:.74rem;font-weight:700;color:${barColor};flex-shrink:0">${pct}%</span>
|
||||
</div>
|
||||
<div class="si-bar" style="margin:0"><div class="si-fill ${barCls}" style="width:${pct}%"></div></div>
|
||||
</div>`;
|
||||
}).join('');
|
||||
}catch(e){
|
||||
list.innerHTML='<div style="color:var(--red);font-size:.82rem">Fehler beim Laden.</div>';
|
||||
}
|
||||
}catch(e){}
|
||||
}
|
||||
|
||||
// -- Kopier-Verlauf -----------------------------------------------------------
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.0.69
|
||||
1.0.70
|
||||
|
||||
Reference in New Issue
Block a user