From 900d8a137c7c82a3f42ecabdc291310f9563d538 Mon Sep 17 00:00:00 2001 From: Roman Tarasov Date: Sat, 3 Oct 2026 14:28:59 +0300 Subject: [PATCH] Fix storage overview duplicates and show the internal drive --- docs/api.md | 5 +++++ web/index.html | 21 ++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/docs/api.md b/docs/api.md index e800dee..a0905ef 100644 --- a/docs/api.md +++ b/docs/api.md @@ -143,6 +143,11 @@ available for new files; `used_bytes` is calculated against that value. The `/mnt/ext*` and `/mnt/usb*` roots are included as additional destinations. Each item adds the selectable `path` to the same filesystem metadata. +The web storage overview uses `mounts` to show the internal `/user` filesystem +and mounted `/mnt/ext0..1` and `/mnt/usb0..7` disks once per filesystem/source. +System partitions and game mounts are omitted from that overview. The separate +`destinations` list supplies folder choices for copying, moving and unpacking. + `copy` and `move` preserve the source basename and require an existing destination under a configured non-runtime scan root. They and `delete` return HTTP 202 with a `job_id` and continue in one background worker; diff --git a/web/index.html b/web/index.html index 89271df..5cf3698 100644 --- a/web/index.html +++ b/web/index.html @@ -1304,10 +1304,21 @@ const list = $("storageList"); try { const data = await api("/storage"); - const mounts = (data.destinations || []).slice().sort((left, right) => + state.storageDestinations = (data.destinations || []).slice().sort((left, right) => String(left.path).localeCompare(String(right.path)) ); - state.storageDestinations = mounts; + const seen = new Set(); + const mounts = (data.mounts || []).filter((mount) => + mount.mount_point === "/user" || /^\/mnt\/(?:usb[0-7]|ext[01])$/.test(mount.mount_point) + ).sort((left, right) => + (right.mount_point === "/user") - (left.mount_point === "/user") || + left.mount_point.localeCompare(right.mount_point) + ).filter((mount) => { + const key = JSON.stringify([mount.filesystem, mount.source || mount.mount_point]); + if (seen.has(key)) return false; + seen.add(key); + return true; + }); if (!$("destinationModal").hidden) renderDestinationPicker(); list.replaceChildren(); if (!mounts.length) { @@ -1322,8 +1333,8 @@ const freePercent = 100 - usedPercent; const row = node("div", "storage-row"); const head = node("div", "storage-head"); - const path = node("span", "storage-path", mount.path); - path.title = mount.path; + const path = node("span", "storage-path", mount.mount_point); + path.title = mount.mount_point; head.append(path, badge(mount.filesystem || "FS", "live")); row.append(head); const meta = node("div", "storage-meta", `${mount.filesystem || t("unknown")} · ${mount.source || "—"}`); @@ -1335,7 +1346,7 @@ row.append(space); const meter = node("div", "storage-meter"); meter.setAttribute("role", "progressbar"); - meter.setAttribute("aria-label", t("storageUsed", { path: mount.path })); + meter.setAttribute("aria-label", t("storageUsed", { path: mount.mount_point })); meter.setAttribute("aria-valuemin", "0"); meter.setAttribute("aria-valuemax", "100"); meter.setAttribute("aria-valuenow", String(Math.round(usedPercent)));