Skip to content

fix: land on device source and stop indexing mounted disks - #8

Merged
cyberb merged 3 commits into
masterfrom
device-source-first
Aug 22, 2026
Merged

fix: land on device source and stop indexing mounted disks#8
cyberb merged 3 commits into
masterfrom
device-source-first

Conversation

@cyberb

@cyberb cyberb commented Aug 20, 2026

Copy link
Copy Markdown
Member

Reported at https://syncloud.discourse.group/t/files-nothing-to-show-here/670 — the new Files app opens on "nothing to show here", and the sidebar shows device at 1.8 TB / 118.8 GB (1580%).

Landing source

New users get their scopes in config source order (settings builds DefaultScopes by iterating Server.Sources), and the UI lands on scopes[0] (Files.vue redirects /files to /files/${sources.current}, mutations.setSources sets current = user.scopes[0].name). files was first, and /data/files is created empty by InitStorage, so a fresh login landed on an empty folder. The old Python app started at /.

device is now first, so the first screen has content and files is one click away in the sidebar.

Usage bar / indexing

The device source is rooted at /. Its bar divides UsedAsIndexed (summed from the index walk) by DiskTotal (statfs of the partition holding the source root). The walk descends into /opt/disk, so on a device with an external disk the entire disk is counted against the system partition — hence 1580%.

The percentage is cosmetic; the cost is not. Every scan re-walks the whole external drive, on a home NAS, indexing content the files source already covers.

/opt/disk and the platform's /data symlink to it are now excluded from indexing on the device source, with viewable: true so browsing still works. During a routine scan an exact folderPath match prunes the subtree; viewable keeps the API path accessible.

Testing

The UI journey now waits for /files/device after login rather than clicking the source button, so a regression in landing order fails CI.

The percentage itself is not covered: CI platform images are single-disk, so used and total come from the same partition and the >100% condition cannot arise. Verified the rule semantics against upstream v1.4.0-stable instead.

Not covered here

Scopes are persisted per user at account creation and the OIDC login path only updates Permissions for an existing user, so accounts created before this change keep files first and will still land on the empty source. Fixing those needs a scope migration against the bolt DB, which is deliberately out of scope for this PR.

cyberb added 2 commits August 20, 2026 19:19
New users get their scopes in config source order (settings builds
DefaultScopes by iterating Server.Sources) and the UI lands on
scopes[0], so a fresh login opened the empty /data/files source and
showed "nothing to show here". The old app started at /, so this read
as a regression. Put device first, and assert the landing source in
the UI journey instead of clicking past it.

The device source is rooted at / and its usage bar divides an
index-walk sum by a statfs of the root partition. The walk descends
into /opt/disk, so on a device with an external disk the whole disk
was counted against the system partition -- a user reported
1.8 TB / 118.8 GB (1580%) -- and every scan re-walked terabytes of
content the files source already covers. Exclude the mount point and
its /data symlink from indexing, viewable so browsing still works.

Refs https://syncloud.discourse.group/t/files-nothing-to-show-here/670
The welcome prompt is gated on ShowFirstLogin, set at user creation to
IsFirstLoad && admin, and IsFirstLoad is true only when filebrowser had
no database file at startup. After an upgrade the store version has
already created the database, so the user created at first login never
gets the prompt and the unconditional wait times out.

This only started biting now: the upgrade test installs the released
app from the store, and until that became FileBrowser Quantum the old
side was the legacy python app, which creates no filebrowser database.
The spec would fail on master untouched.

Dismiss the prompt through a locator handler so the run works whether
or not it appears, instead of racing its arrival.
@cyberb

cyberb commented Aug 20, 2026

Copy link
Copy Markdown
Member Author

Verification

CI: build 190 green on all three pipelines (amd64/arm64/arm), including test-ui-desktop and test-ui-after-upgrade.

Landing source — after-upgrade screenshot (190-amd64/screenshots-buster/02-logged-in.png) shows the sidebar as device then files, with the app landed on the device root listing boot etc home opt snap var …. The spec's waitForURL('/files/device') is what gates this now.

Exclusion rule — CI can't cover this (its platform images are single-disk, so used and total come from the same partition and the >100% condition cannot arise), so I ran the shipped v1.4.0-stable binary directly against a tree with a 64 MB file in the folder being excluded:

numDirs numFiles root size /mnt browsable
no rule 2 2 67112960 yes
folderPath: /mnt, viewable: true 1 1 8192 yes

The excluded subtree drops out of the index and out of the size aggregate, and stays fully browsable through the API — which is the behaviour this fix depends on.

One correction to the description above: used is not a raw walk sum. GetIndexInfo (indexing/mutate.go:296-319) sums the source root's immediate children — file sizes directly, folder sizes via the aggregate — so excluding /opt/disk removes it from that sum by keeping it out of the index DB entirely.

Second commit

test-ui-after-upgrade failed on the first push, and it was pre-existing rather than caused by the reorder. The welcome prompt is gated on ShowFirstLogin, set at user creation to IsFirstLoad && admin (database/storage/storage.go:109), and IsFirstLoad is true only when filebrowser found no database file at startup (:47-52). The upgrade test installs the released app from the store first; once that became Quantum it creates the database, so the upgraded instance starts with IsFirstLoad=false and the user created at first login never sees the prompt. While the store still held the legacy python app there was no filebrowser database, which is why 187 and 188 passed. The spec would fail on master untouched.

Now dismissed through a locator handler, so the run works whether or not the prompt appears — confirmed by the artifacts: the fresh-install run has 01-first-login-welcome.png, the after-upgrade run does not, and both complete every later step.

@cyberb

cyberb commented Aug 20, 2026

Copy link
Copy Markdown
Member Author

Verified on real hardware (borisarm64), and one correction

Installed build 190 (files 190, arm64) on a device with the same topology as the report: 30 GB root, a 1.9 TB external disk at /opt/disk/external with 274 GB used, /data symlinked to it.

The exclusion works. Queried the index DB (cache/sql/index_all.db) after the scan settled:

  • device source: 441,766 items, summing to 25.5 GB against a 30 GB root partition — under 100%, where before it would have added the external disk's 274 GB against the same 30 GB.
  • Rows under /opt/disk* or /data*: exactly one, /data itself, recorded as a zero-size blob (the symlink). Nothing beneath it.
  • /opt has no indexed children at all.
  • Scan completed in under 30 s instead of grinding through the external disk.

Correction to the "not covered here" note in the description. I claimed existing users keep files first because scopes are persisted at creation. That is wrong. cmd/user.go:80-124 (updateUserScopes) runs for every user on every startup and rebuilds the scope list in Config.Server.Sources order, preserving each user's scope value. The device confirms it — its pre-existing user now has scopes: [{"/","/"},{"/data/files","/"}], device first, without any migration.

But the caveat survives, via a different field. Files.vue:443-452 prefers the first source-category entry in user.sidebarLinks over sources.current when redirecting /files, and updateSidebarLinks (cmd/user.go:217-240) only rebuilds those links when none of them still resolve. So an existing user keeps their old link order and still lands on files. Same device: sidebarLinks: [files, device] while scopes are device-first.

That also explains the reporter's screenshot, where files sits above device in the sidebar — that ordering is the sidebar links, not the sources config.

So: new installs land on device (proven by CI on both fresh install and after upgrade); existing users keep their sidebar order and can reorder it themselves via the edit control on the Links panel, or just click device. Fixing it for them would mean rewriting source sidebar links in the bolt DB, still out of scope here.

@cyberb
cyberb merged commit 9db2675 into master Aug 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant