Skip to content

System Storage: show available space per root folder, app data and system disk (#508)#656

Merged
therobbiedavis merged 6 commits into
Listenarrs:canaryfrom
s3ntin3l8:508-storage-per-root-folder
Jun 9, 2026
Merged

System Storage: show available space per root folder, app data and system disk (#508)#656
therobbiedavis merged 6 commits into
Listenarrs:canaryfrom
s3ntin3l8:508-storage-per-root-folder

Conversation

@s3ntin3l8

@s3ntin3l8 s3ntin3l8 commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Fixes #508

Summary

The System page's Storage card previously reported only the disk hosting the application — in Docker/NAS setups that's a small boot/app device (e.g. a 4 GB USB DOM), while the audiobook library lives on a separate mount that was never shown. This adds per-disk reporting so the System page shows available space for the System disk, the App Data (config) volume, and every configured root folder.

Changes

Added

  • GET /api/v1/system/storage now returns a disks[] array with an independently-measured entry for the System disk (container root, e.g. docker.img on Unraid), the App Data disk (config volume holding the database/logs/cache), and each configured root folder (one row per folder, no dedupe). Missing or inaccessible paths yield an unavailable entry instead of failing the request.
  • System page Storage card renders these as a stacked per-disk list: label + mount point, a full-width usage bar, and free of total per row.
  • IDiskSpaceProbe seam abstracting disk measurement — Windows GetDiskFreeSpaceEx (handles drive paths, mounted-folder junctions, and UNC/NAS shares) with a DriveInfo/statvfs fallback on Unix — so NAS roots are measured and the logic is unit-testable.
  • Defensive clamping of used bytes/percentage for filesystems that report free space exceeding total (reserved blocks, over-provisioning, ZFS/Btrfs, network shares).

Changed

  • Legacy top-level StorageInfo fields are retained for compatibility but now describe the App Data disk (config volume); driveName carries that path (was DriveInfo.Name, e.g. /). Per-disk detail is in disks[]. API consumers relying on these fields should note the changed meaning.
  • ProgressBar's size formatter gains a TB unit (multi-terabyte mounts previously displayed as thousands of GB).

Fixed

Removed

  • The Storage card's summary badge — it could only headline a single disk; the per-disk list now shows each disk's free/total concisely.

Screenshots

image

Testing

  • Backend (SystemServiceStorageTests, hermetic via temp dirs): no root folders, config-root measurement and content-root fallback, multiple folders on one filesystem, missing path → unavailable, UNC path measured via a fake probe (available + unavailable), and an over-provisioned disk → usage clamped to zero.
  • Backend (DiskSpaceProbeTests): the real DriveInfo branch on an existing temp dir and a missing path. The Windows GetDiskFreeSpaceEx call can't run on Linux CI, so that path is review-covered.
  • Frontend: StorageDisksList.spec.ts (per-disk rows, free-of-total, unique keys, unavailable) and ProgressBar.spec.ts (TB / sub-TB formatting).
  • Full suites green: 691 backend / 368 frontend, plus dotnet format, vue-tsc, ESLint, Prettier.
  • Verified end-to-end in Docker and on an Unraid deployment with the library on a separate mount.

Notes

  • This PR needs a version label for the Validate PR version label check — I don't have triage rights to add it.
  • No CHANGELOG.md entry, per the no-changelog-on-upstream-PRs policy.

🤖 Generated with Claude Code

@therobbiedavis therobbiedavis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix here. I left a couple of small review notes around edge cases/UX polish; nothing huge, but worth tightening before merge.

Comment thread listenarr.infrastructure/Platform/SystemService.cs Outdated
Comment thread fe/src/components/system/StorageDisksList.vue Outdated
Comment thread fe/src/components/system/StorageDisksList.vue
@therobbiedavis therobbiedavis self-assigned this Jun 8, 2026
@s3ntin3l8 s3ntin3l8 requested a review from therobbiedavis June 8, 2026 11:09

@therobbiedavis therobbiedavis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but there is one non-blocking request: Could we pull the Windows path/native-call handling behind a tiny testable seam and add coverage for UNC inputs? I’m not asking because I reproduced a failure: I tested GetDiskFreeSpaceExW against a temporary elevated local SMB share and it succeeded with and without a trailing slash. This is more about keeping the NAS-support behavior from regressing later.

@s3ntin3l8

Copy link
Copy Markdown
Contributor Author

Done in 1bbdc329. Pulled the Windows GetDiskFreeSpaceEx handling behind a small IDiskSpaceProbe seam (interface in application, impl in infrastructure) so SystemService no longer branches on OS. Added tests that drive a UNC path through the measurement pipeline (available + unavailable) plus probe tests for the Unix/DriveInfo branch — the native call itself still can't run on Linux CI, so that one line stays review-covered.

Same commit also tightens a few small things: clamp used bytes/percentage so filesystems reporting free > total (over-provisioning, ZFS/Btrfs, network shares) can't go negative; XML-doc the legacy top-level StorageInfo fields as describing the App Data disk; drop the now-redundant Storage card summary badge (the per-disk list covers it); and add ProgressBar TB-formatting tests.

@therobbiedavis therobbiedavis added the patch patch version bump - backward compatible bug fixes label Jun 9, 2026
@therobbiedavis

Copy link
Copy Markdown
Collaborator

@s3ntin3l8 LGTM. Can you update the PR description to match the template? We should be good to merge after that.

@s3ntin3l8

Copy link
Copy Markdown
Contributor Author

@s3ntin3l8 LGTM. Can you update the PR description to match the template? We should be good to merge after that.

@therobbiedavis: Done and ready to merge

s3ntin3l8 and others added 6 commits June 9, 2026 08:01
GET /api/v1/system/storage now returns a disks array alongside the
existing fields: the System disk (container root, e.g. docker.img on
Unraid), the App Data disk (config volume holding database/logs/cache),
and one entry per configured root folder. Each disk is measured with
DriveInfo on the path itself so Docker volume mounts report their own
filesystem instead of the container root's.

Missing or inaccessible paths yield an 'unavailable' entry instead of
failing the request. The legacy top-level fields now describe the App
Data disk (config volume) rather than the install-path root, and
DriveName carries that path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Storage card now renders one entry per disk from the new disks
array — label and mount point, a full-width usage bar, and the
percentage / used-of-total line — via a new StorageDisksList component.
ProgressBar's size formatter gains a TB unit so multi-terabyte mounts
no longer display as thousands of GB.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Listenarrs#508)

DriveInfo throws on UNC/NAS roots (\\server\share), so those reported
as unavailable. On Windows, measure any directory — drive paths,
mounted-folder junctions, and UNC shares — via GetDiskFreeSpaceExW.
Unix keeps DriveInfo (statvfs). Disk-info construction is now shared
through a BuildDiskInfo helper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address PR review:
- Composite v-for key (label:path:index) so a configured root folder
  sharing a path with the System/App Data entry no longer triggers a
  duplicate-key warning.
- Each row shows free-of-total capacity (Listenarrs#508 is about available space),
  replacing the bar's used/total readout; the percentage stays.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Extract disk-space measurement behind an IDiskSpaceProbe seam so the
  Windows GetDiskFreeSpaceEx path is unit-testable; cover UNC inputs.
- Clamp used bytes/percentage so filesystems reporting free > total
  (reserved blocks, over-provisioning, ZFS/Btrfs, network shares) cannot
  go negative; add an over-provisioned test.
- Document the legacy top-level StorageInfo fields as describing the App
  Data disk, with per-disk detail in Disks; fix the disk-order comment.
- Drop the Storage card summary badge (it headlined the least useful
  disk); the per-disk list already shows each disk's free/total.
- Add ProgressBar TB-formatting tests.
- Remove the CHANGELOG entry per repo policy (no changelog on upstream PRs).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@therobbiedavis therobbiedavis force-pushed the 508-storage-per-root-folder branch from 1bbdc32 to 04a2cd6 Compare June 9, 2026 12:03
@therobbiedavis therobbiedavis merged commit 5f8adc4 into Listenarrs:canary Jun 9, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

patch patch version bump - backward compatible bug fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

System Storage: Show available space on a root folder basis too

2 participants