diff --git a/backend/package-lock.json b/backend/package-lock.json index 5d66d88..85609e8 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "ripster-backend", - "version": "0.10.2-5", + "version": "0.10.2-6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ripster-backend", - "version": "0.10.2-5", + "version": "0.10.2-6", "dependencies": { "archiver": "^7.0.1", "cors": "^2.8.5", diff --git a/backend/package.json b/backend/package.json index 25c265e..4d678de 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "ripster-backend", - "version": "0.10.2-5", + "version": "0.10.2-6", "private": true, "type": "commonjs", "scripts": { diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d63a6a2..b904ea9 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -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", diff --git a/frontend/package.json b/frontend/package.json index 8ffabba..d118b4c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "ripster-frontend", - "version": "0.10.2-5", + "version": "0.10.2-6", "private": true, "type": "module", "scripts": { diff --git a/frontend/src/pages/DashboardPage.jsx b/frontend/src/pages/DashboardPage.jsx index 81e5fe4..3085dae 100644 --- a/frontend/src/pages/DashboardPage.jsx +++ b/frontend/src/pages/DashboardPage.jsx @@ -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) => ( -
- {options.chooseButton} - {options.cancelButton} -
- )} + 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) => (
diff --git a/frontend/src/styles/app.css b/frontend/src/styles/app.css index c7190ed..929192f 100644 --- a/frontend/src/styles/app.css +++ b/frontend/src/styles/app.css @@ -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; } diff --git a/package-lock.json b/package-lock.json index b788389..2b8aedd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ripster", - "version": "0.10.2-5", + "version": "0.10.2-6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ripster", - "version": "0.10.2-5", + "version": "0.10.2-6", "devDependencies": { "concurrently": "^9.1.2" } diff --git a/package.json b/package.json index c99f797..4a5960c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ripster", "private": true, - "version": "0.10.2-5", + "version": "0.10.2-6", "scripts": { "dev": "concurrently \"npm run dev --prefix backend\" \"npm run dev --prefix frontend\"", "dev:backend": "npm run dev --prefix backend",