0.10.2-6 Layout

This commit is contained in:
2026-03-16 08:20:50 +00:00
parent 01766785b4
commit 168484b5d9
8 changed files with 38 additions and 31 deletions

View File

@@ -1,12 +1,12 @@
{
"name": "ripster-frontend",
"version": "0.10.2-5",
"version": "0.10.2-6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ripster-frontend",
"version": "0.10.2-5",
"version": "0.10.2-6",
"dependencies": {
"primeicons": "^7.0.0",
"primereact": "^10.9.2",

View File

@@ -1,6 +1,6 @@
{
"name": "ripster-frontend",
"version": "0.10.2-5",
"version": "0.10.2-6",
"private": true,
"type": "module",
"scripts": {

View File

@@ -880,18 +880,38 @@ export default function DashboardPage({
const gpuMetrics = monitoringSample?.gpu || null;
const storageMetrics = Array.isArray(monitoringSample?.storage) ? monitoringSample.storage : [];
const storageGroups = useMemo(() => {
const groups = [];
// Phase 1: group by mountPoint
const phase1 = [];
const mountMap = new Map();
for (const entry of storageMetrics) {
const groupKey = entry?.mountPoint || `__no_mount_${entry?.key}`;
if (!mountMap.has(groupKey)) {
const group = { mountPoint: entry?.mountPoint || null, entries: [], representative: entry };
mountMap.set(groupKey, group);
groups.push(group);
phase1.push(group);
}
mountMap.get(groupKey).entries.push(entry);
}
return groups;
// Phase 2: merge groups with identical disk signature (same physical disk)
const merged = [];
const diskSigMap = new Map();
for (const group of phase1) {
const totalBytes = Number(group.representative?.totalBytes);
const freeBytes = Number(group.representative?.freeBytes);
if (Number.isFinite(totalBytes) && totalBytes > 0 && Number.isFinite(freeBytes)) {
const sig = `${totalBytes}:${freeBytes}`;
if (diskSigMap.has(sig)) {
diskSigMap.get(sig).entries.push(...group.entries);
} else {
diskSigMap.set(sig, group);
merged.push(group);
}
} else {
merged.push(group);
}
}
return merged;
}, [storageMetrics]);
const cpuPerCoreMetrics = Array.isArray(cpuMetrics?.perCore) ? cpuMetrics.perCore : [];
const gpuDevices = Array.isArray(gpuMetrics?.devices) ? gpuMetrics.devices : [];
@@ -2495,19 +2515,15 @@ export default function DashboardPage({
ref={audiobookFileUploadRef}
accept=".aax"
maxFileSize={10737418240}
customUpload
uploadHandler={() => void handleAudiobookUpload()}
disabled={audiobookUploadBusy}
onSelect={(e) => setAudiobookUploadFile(e.files[0] || null)}
onClear={() => setAudiobookUploadFile(null)}
onRemove={() => setAudiobookUploadFile(null)}
chooseLabel="Auswählen"
chooseOptions={{ icon: 'pi pi-folder-open' }}
cancelOptions={{ icon: 'pi pi-times', className: 'p-button-outlined p-button-secondary' }}
headerTemplate={(options) => (
<div className="aax-upload-header">
{options.chooseButton}
{options.cancelButton}
</div>
)}
chooseOptions={{ icon: 'pi pi-images', iconOnly: true, className: 'p-button-rounded p-button-outlined' }}
uploadOptions={{ icon: 'pi pi-cloud-upload', iconOnly: true, className: 'p-button-rounded p-button-outlined p-button-success' }}
cancelOptions={{ icon: 'pi pi-times', iconOnly: true, className: 'p-button-rounded p-button-outlined p-button-danger' }}
itemTemplate={(file, options) => (
<div className="aax-file-item">
<i className="pi pi-headphones aax-file-icon" />

View File

@@ -1112,15 +1112,6 @@ body {
white-space: normal;
}
.aax-upload-header {
display: flex;
gap: 0.5rem;
padding: 0.5rem 0.75rem;
border-bottom: 1px solid var(--rip-border);
background: var(--rip-panel-soft);
border-radius: 0.5rem 0.5rem 0 0;
}
.aax-drop-zone {
display: flex;
flex-direction: column;
@@ -3659,7 +3650,7 @@ body {
.runtime-activity-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-template-columns: minmax(0, 1fr);
gap: 0.75rem;
}