0.10.2-6 Layout
This commit is contained in:
@@ -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" />
|
||||
|
||||
Reference in New Issue
Block a user