2226 Commits
Author SHA1 Message Date
Luke Childs 9298257b0e umbrelOS 2.0 2026-09-22 20:00:29 +07:00
github-actions[bot] a3dbf0bf17 Update translations for staging 2026-09-22 20:43:54 +08:00
Luke Childs 757065961e Allow 4 GB RAM for Ubuntu Desktop machines
Lower the Ubuntu Desktop creation minimum from 6 GB to 4 GB while
keeping the 8 GB default. Ubuntu's 6 GB guidance targets a comfortable
desktop experience and explicitly allows installation on lower-spec
systems; update the profile comments to reflect that distinction.

Formatting and whitespace checks pass. A fresh installation and
first-boot setup with 4 GB RAM have not been tested.
2026-09-22 19:13:42 +07:00
Luke Childs eef7bc66de Fix Machine image downloads on slow connections
Machine image downloads can fail on a working IPv4 connection when the
TCP handshake takes more than 250 ms and the final fallback address is
unreachable IPv6. Give each address attempt one second in the shared
HTTP/HTTPS downloader, including redirects and supplemental resources,
while preserving validated DNS pinning and address fallback. Unreachable
addresses can consequently take up to one second before the next
attempt.

When all connection attempts fail, give Node's message-less
AggregateError a translated connection-failure message so the Machines
UI displays useful guidance. Preserve the original error as the cause
for diagnostic logs.

Add Linux integration coverage with an isolated network namespace, two
working IPv4 addresses, unreachable IPv6, and a 400 ms TCP handshake.
Each scenario first reproduces the original 250 ms failure, then
verifies the downloader succeeds directly or through a redirect,
including file contents, SHA-256, and temporary-file cleanup. Unit
coverage also checks that exhausted address lists produce a useful error
without losing their underlying causes.
2026-09-22 19:09:39 +07:00
Luke Childs c48c80c9e8 Remove restrictive timeout on umbreld proxy server
Uploads through Umbrel's proxies can fail with HTTP 408 after roughly
five minutes even while data is still arriving. LAN ingress and the app
gateway inherit Node's 300-second request deadline, overriding upstream
support for long uploads and creating an apparent file-size limit that
varies with transfer speed.

Disable `requestTimeout` in the shared HTTP and HTTPS LAN ingress proxy
factories and in the app gateway. This covers umbreld APIs, apps reached
directly through ingress, and apps behind gateway authentication.
Long-running request bodies rely on umbreld or the upstream app's
timeout policy; separate header timeouts and explicitly configured app
proxy timeouts remain in place.

Add regression coverage using real HTTP and HTTPS connections with
shortened Node deadlines. The tests exercise continuously streaming
uploads both with and without the authenticated app gateway, check that
file contents arrive intact and header timeouts are retained, and verify
that upstream servers can still enforce their own upload deadlines.
Gateway HTTP traffic goes directly to the gateway; gateway HTTPS traffic
passes through LAN ingress first. The upload regressions reproduce HTTP
408 failures before the corresponding fixes.
2026-09-22 18:57:51 +07:00
Luke Childs af1be745bc Update libheif to 1.23.4 to resolve HEIF Heist vuln
Updates the OS image decoder from libheif 1.19.8 to 1.23.4 so Files and
Photos receive the upstream fixes when generating HEIF/AVIF thumbnails.

Installs a pinned set of Debian packages for amd64 and arm64 from the
September 21 snapshot, with SHA-256 verification. The matching libheif
plugins and required sharpyuv/x265 libraries preserve existing image
encoding and decoding support. Installation uses APT with package
removal disabled, followed by checks for the installed versions and
ImageMagick's HEIC/HEIF/AVIF support. The existing libde265 1.1.1
override remains in place.
2026-09-22 18:56:34 +07:00
Mayank Chhabra 920ec6a65a Update What's New modal and link to the keynote 2026-09-22 19:24:42 +08:00
Mayank Chhabra b3b39115e1 Keep the Photos grid one width when the time rail hides the scrollbar
With classic scrollbars (Windows, Linux, a Mac set to always show them)
the listing scroller reserves the scrollbar's strip with
scrollbar-gutter so content coming and going can't resize the grid. But
when the time rail appeared it hid the scrollbar with scrollbar-width:
none, which releases the gutter too: the scroller grew by the
scrollbar's width a beat after the tiles appeared and the grid snapped
wider - every tile a little bigger, the right edge out by a full gutter.

FadedScroller now owns hiding the scrollbar (hideScrollbar) and keeps
the strip as padding of the same width while it is hidden, so the grid's
width is identical whether the scrollbar or the rail occupies the edge.
With overlay scrollbars nothing changes. The scrollbar measurement that
feeds the fade mask re-runs on hide/show, since neither box changes
size.
2026-09-22 14:55:55 +08:00
Nathan Fretz 06d35b2532 Fetch the app catalog over HTTP so slow links can load the dashboard
The ~1 MB catalog went over the tRPC WebSocket, whose 10 s ping / 3 s pong
keepalive queues the pong behind the payload. On a slow link the browser
closed the socket partway through every attempt and the dashboard ended on
"Failed to fetch apps". Routing appStore.registry through httpOnlyPaths
fetches it with a plain HTTP request, which has no keepalive. Throttled to
200/100 kbps with 400 ms latency, the dashboard now loads in about 40 s
instead of failing after a minute.

This is an interim fix: the desktop still waits for the catalog before
rendering.
2026-09-22 16:53:02 +10:00
Mayank Chhabra 876d6338e3 Stop requesting directory listings for Search, Recents, and Cloud views
The shared context menu and rename controls mount useListDirectory on
these client-only routes, whose items come from other APIs. The backend
rejects those paths with [invalid-base], and errored queries refetch on
every observer mount, so each row that mounted on Search or Recents
re-fired a failing request.

Disabling the query alone would keep the previous folder's listing (and
its writable capability) in place as placeholder data, so the hook now
drops data, placeholder, loading, error, and pagination for those roots.
2026-09-22 14:04:41 +08:00
Nathan Fretz 1a47f31fc2 Say no active downloads when a cloud has no tracked folders
After a one-time cloud download finishes, its record is removed on
purpose so the folder becomes a regular editable one. The Cloud views
then said "No downloads yet" even though the downloaded folder was right
there in Files.

- Cloud root tile: "No active downloads".
- Account page and account dialog: "No active downloads from this cloud.
One-time downloads become regular folders and don't appear here."
2026-09-22 15:54:11 +10:00
Nathan Fretz ef8fa439a5 Keep discovered devices three across in the network share dialog
In Chrome the Add network share dialog laid out discovered devices two
across with a wide gap between them, while Safari showed three across.

The dialog gives the grid 416px and three stretching columns need 407px.
The scroll wrapper reserves a stable scrollbar gutter, which is 11px in
Chrome and nothing in Safari, so Chrome came up two pixels short and
dropped to two columns.

- Use fixed 125px columns with a 12px gap, the same grid the Backups
wizard's device step already uses for these cards. Three across needs
399px and fits in both browsers.

The dialog is shared by Files, both Backups wizards, and onboarding
restore.
2026-09-22 15:39:39 +10:00
Nathan Fretz bb48bb0715 Run the constellation orbits on the compositor
The MCP and Cloud constellations animated each satellite's x, y and
scale as separate values, which Motion drives from its own JavaScript
frame loop. Any main-thread stall longer than a frame made the orbit
jump ahead; in Safari the MCP pitch's chat replay caused visible dropped
frames on every bubble.

- Animate one `transform` keyframe list per satellite, so Motion hands
the loop to the Web Animations API and it runs on the compositor.
- Replace the `zIndex` keyframes, which Motion never animated, with the
fixed value they always resolved to. The look is unchanged.
- The pitch to picker morph is unaffected: the tiles remount on the view
switch and Motion snapshots the outgoing element with its live
transform.
2026-09-22 15:10:03 +10:00
Nathan Fretz 5cbc55fc3f Polish search, Settings, and sheet UI
- Truncate long album and date names in the Photos search pills instead
of letting them spill out.
- Show a minimum length error when creating a user or resetting a
member's password, instead of a silently disabled button.
- Stop the App Store search field flickering between keystrokes: the
hook no longer adopts its own late URL writes. With regression coverage.
- Clip the sheet wallpaper to the rounded corners, so Safari no longer
shows square corners while a sheet opens.
- Keep the App Store menu button clear of the sheet close button on
phones.
- Add an exit button to Files search that returns to the folder the
search started from, and make Escape do the same instead of stepping
back through browser history.
2026-09-22 15:09:23 +10:00
Mayank Chhabra b1d47a1e9d Polish pickers, file sharing, and system UI
- Unify app, machine, and language pickers with consistent search,
keyboard navigation, and focus handling.
- Preserve wheel and touch scrolling in pickers inside modal dialogs,
with regression coverage.
- Introduce Umbrel for Mac in the welcome desktop and file-sharing
instructions with Finder previews and download links.
- Automatically select file-sharing instructions for the current device
and simplify dialog scrolling and dismissal.
- Cap displayed CPU usage at 100% and refine system app icons in Live
Usage.
- Format upload progress to two decimal places and simplify
network-share rows and sharing-list gutters.
- Restore visible terminal scrollbars and update the terminal notice to
reflect restart persistence and recommend Machines.
2026-09-22 05:30:14 +08:00
Mayank Chhabra c75a7f0b2f Rework storage failure, recovery, and drive replacement flows
Storage screens assumed Umbrel Pro hardware, treated a failed read as
"nothing wrong", and made reassurances the UI could not back up. They
are now hardware-aware and explicit about what is and is not known.
Frontend only: no umbreld APIs change.

Boot and onboarding

- The boot storage error page no longer shows the Pro tray and SSD copy
on generic hardware. It lists every configured and connected drive,
including missing and slotless ones, with presence and pool status kept
separate. Pro artwork stays for confirmed Pro devices, and factory reset
moves out of the numbered troubleshooting steps.
- The mount-failure guard no longer fails open. An unanswered check
retries, then shows a neutral connection screen that keeps rechecking. A
failed background recheck leaves an established page alone.
- Drive detection and account creation stop treating failed identity or
inventory reads as "no drives". They show a retryable error instead of
silently routing to a different setup path.
- Restoring an existing install tells a rejected request apart from a
lost response, follows the restart lifecycle without ever repeating the
mutation, and stays mounted through reboot-time read failures. Initial
setup handles a lost register response the same way.
- Long waits show neutral "still working" help after five minutes with a
confirmed "Return to start" exit. A failed restore keeps "Set up as
new".
- Restore screens list drives with health access on mobile. Onboarding
cards scroll within the viewport, and HDD selection steps keep their
action footer pinned.

Storage Manager

- Swap guidance is gated on the redundancy that actually remains. The
surviving member of a degraded mirror or RAIDZ is never offered for
removal, blanket "no backup needed" assurances are gone, and hot-swap
and spare-slot assumptions are removed. Members that are already absent
skip the removal gate and get insertion instructions.
- Loading, failed reads, and unavailable or unidentifiable pools render
a retryable view instead of nothing, and a failed background poll no
longer unmounts an open repair flow. An all-missing stripe is no longer
guessed to be an SSD pool.
- SSD pools show fallback cards for missing members and for Pro drives
without a known slot. Every member shares one action path: a fitting
spare, then in-place repair, then insertion instructions.
- Rejected operations and FailSafe transition errors persist as a
dismissible notice rather than only a toast. Unknown SMART telemetry is
no longer drawn as a passed health check.
- Other Drives explains why a drive can't be added for each hardware and
pool type, and a read-only USB Drives section shares the external-device
hook now extracted from Files.
2026-09-22 05:23:15 +08:00
Mayank Chhabra fee9bd7d22 Upgrade rclone to 1.75.1 for Cloud
Also fixes a case where Apple accepts a valid 2FA code but returns HTTP
409, causing login to fail.
2026-09-22 01:57:59 +08:00
Nathan Fretz a71883bac2 Fix Files move cleanup and rename following
Files could leave moved files visible in their original folder and lose
track of the selected row after a rename.

- Remove successfully moved sources from loaded later pages, and prevent
older requests or cached pages from restoring them.
- Follow renames once within the loaded range, with enough space to keep
the last row clear of the bottom fade. Beyond that range, preserve
selection but hide the temporary row until normal paging reaches it,
without a delayed jump.
- Arrow keys keep the user's place after a rename hidden past the loaded
range instead of jumping to the first item.
- Renaming an unconfirmed rename target retires the intermediate entry,
so it can no longer linger as a phantom row.

Keeps optimistic updates, 250-item paging, and the existing backend.
Finding an arbitrary renamed file in a huge folder would require
scanning pages or backend support; overhauling pagination and caching
would add regression risk beyond these bug fixes. Following uses the
metadata already available, so later metadata changes (such as file type
after changing an extension) may reorder the file without another
scroll.
2026-09-22 00:06:03 +10:00
Nathan Fretz f4a4aa6d87 Combine default credentials and HTTPS app launch prompts
Apps that require HTTPS and provide default credentials could fail to
open because closing the credentials dialog cleared the HTTPS dialog
that followed it. Combine both prompts into one adaptive launch dialog,
preserving independent preferences and deep links. Credentials remain
available in App Settings when the launch prompt is disabled.
2026-09-21 21:25:59 +10:00
Mayank Chhabra 90ebf2af06 Unify global dialogs and improve modal keyboard and clipboard behavior
- Open Terminal and Troubleshoot over any page, preserving the
   underlying view and redirecting existing Settings URLs.
- Mount Logout, Live Usage, What's New, Terminal, and Troubleshoot
   through a shared lazy-loaded host, with prefetching and owner-only 
   access where required.
- Clear stale dialog parameters when opening, switching, or closing
   dialogs while preserving unrelated page parameters.
- Enable native clipboard menus in Terminal and Troubleshoot, and
   prevent log auto-scrolling from interrupting text selection.
- Prevent Files shortcuts from acting on content beneath dialogs and
   menus, including when Escape dismisses a modal.
- Add regression coverage for dialog lifecycle, access restrictions,
   picker targets, URL parameters, and modal keyboard handling.
2026-09-21 18:31:55 +08:00
Mayank Chhabraandsurajmahraj 234f001149 Tint the browser chrome with the wallpaper's color
Co-authored-by: surajmahraj <[email protected]>
2026-09-20 19:12:02 +08:00
Luke Childs 93f9bee66e umbrelOS 2.0 Beta 2 2026-09-18 04:19:14 +07:00
Luke Childs feafed9ab1 Maintain folder size totals in the file index
Maintain folder-size totals in the file index so Files listings and
favorites use indexed lookups instead of repeatedly scanning subtrees.
Commit entries and totals atomically, preserving hard-link
deduplication, Trash exclusions and account isolation. Handle files
arriving before their parent directories and discard unused size
bookkeeping.

Backfill existing indexes directly from SQLite without another
filesystem crawl. Route ordinary size lookups through the interactive
readers so they can proceed while slow searches run.

On an Umbrel Pro with approximately 40,000 indexed files, measured
median RPC times improved:

- Home listing: **1.31 s → 7.5 ms (175× faster)**.
- Sidebar favorites: **834 ms → 5.6 ms (150× faster)**.
- Home listing while favorites loads: **2.44 s → 9.7 ms (251× faster)**.

The tradeoff is additional work during indexing: a fresh 100,000-file
crawl took 8.23 → 12.19 seconds locally (48% longer), while unchanged
rescans remained similar.
2026-09-18 04:13:43 +07:00
Luke Childs eff0da31ae Fix app settings tests missing the image cleanup dependency
The app-settings fixture omits `apps.imageCleanup`, so all 11 settings
tests fail with `Cannot read properties of undefined (reading
'runOperation')` before exercising the settings behavior.

Initialize a real `ImageCleanup` with a no-op sweep in the fixture,
matching the app-lifecycle tests and restoring the existing settings
assertions.
2026-09-18 02:24:10 +07:00
github-actions[bot]andmayankchhabra 257adaa8f0 Update translations
Co-authored-by: mayankchhabra <[email protected]>
2026-09-18 02:04:58 +08:00
Mayank Chhabra ef14e878ab Establish translation baseline from the workflow migration 2026-09-18 01:49:53 +08:00
Luke Childs bab0711c0f Run SQLite reads on dedicated read worker threads
Move standalone Files and Photos database reads off the file-index
writer into two read-only workers. Reserve one worker for quick lookups
and let the other handle both quick and expensive queries. Folder-size
calculations, searches, Photos aggregates, and filtered navigation can
no longer occupy every reader, leaving capacity for browsing and
thumbnails.

- Keep mutations, projection maintenance, and reads within write
operations on the writer. Before a Photos read, prepare the projection
and pin consistent snapshots of both databases, then release the writer
while the query runs. Files and enrichment reads bypass this
coordination.
- Let foreground work pass queued scan writes while preserving FIFO
order between user mutations and Photos preparation. Give Files entry
lookups the same priority as on-demand thumbnail metadata, and retain
queued requests during large bursts.
- Start both readers before the index becomes available. Clean up
partial startup failures, recover failed workers, stop readers before
rebuilding the index, and discard Files results when root ownership
changes during a read.
- Serialize background job selection separately so parallel reads cannot
reserve the same enrichment work twice.

Default-cache device tests of this two-reader layout reduced thumbnail
latency during concurrent folder-size queries from roughly 3.6 seconds
to 65 ms compared with one reader, about a 55-fold reduction. Two
readers keep memory use below larger pools while allowing both workers
to serve quick bursts.
2026-09-18 00:49:40 +07:00
Mayank Chhabra 539de9391b Onboarding, Files, Photos, and Machines UI tweaks
- Allow welcome tips to be dismissed individually, with animated
  rearrangement and a Dismiss all action.
- Show indexed folder sizes in Files.
- Offer App Settings and explain overwrite risks before editing an
  app's compose files.
- Cache and limit concurrent Files thumbnail requests, retry failed
  thumbnails, and share authentication across thumbnails.
- Reuse grid thumbnails in the Photos lightbox to reduce image requests,
  hide the active tile, and smooth opening and closing transitions.
- Prevent video playback from starting during a closing transition.
- Hide the phone backup card once a phone connects, with live updates.
- Highlight agent control of Machines in the MCP intro and What's New.
- Add Omarchy artwork for machine states and the OS catalog.
- Add regression coverage for thumbnails, compose file detection,
  lightbox transitions, and phone backup registration.
2026-09-18 01:38:32 +08:00
Luke Childs 1ed77b816d Display Omarchy without the Desktop suffix
Remove Omarchy's `Desktop` variant label so the catalog, creation UI,
MCP, and newly created machines display "Omarchy". Keep VirGL graphics
acceleration available by recognizing the Omarchy OS family explicitly,
as already done for Android.

Existing machines retain their saved OS names. Update the catalog
expectations and cover both the saved name and GPU eligibility without a
variant.
2026-09-18 00:25:59 +07:00
Nathan Fretz 5b3ad7b00f Let MCP agents manage app settings
Granting MCP access to an app already promises control over its
settings. This PR lets agents read and change the settings in Umbrel's
app settings dialog: authentication, folder access, custom mounts,
environment variables, dependency connections, and the
credentials-display preference.

### MCP changes

- `get_app_details` exposes current settings and available options.
`set_app_settings` applies changes through the shared app settings API,
preserving omitted fields and using the existing restart behavior.
- `move_app_data` and `reset_app_data` expose the existing operations
for moving app data or starting fresh when external app data is
unavailable. `get_app_status` reports active operations and failures.
- The existing app grant covers settings. New folder access still
requires file permission, and switching dependency providers requires
access to the selected app. Existing mounts can be retained without
additional grants.

### Shared backend changes

These changes also affect callers outside MCP:

- **Validate dependency selections before saving.** Reject undeclared
dependencies and newly selected providers that are missing or
incompatible. The backend previously trusted these selections. Unchanged
selections remain accepted so stale settings can still be repaired.
- **Preserve spaces in storage paths.** Folder sources and custom mount
targets no longer trim whitespace from actual names. MCP permission
checks and the backend use the same path normalization.
Manifest-declared mount targets retain their existing trimming behavior.
- **Support the credentials preference in the shared settings API.**
`apps.setSettings` accepts `hideCredentialsBeforeOpen`, and `apps.list`
returns the saved preference. The existing UI/UmbrelKit setter remains
unchanged; the shared setter rejects changes during app lifecycle
operations.
- **Allow authentication and credentials-preference changes when storage
is unavailable.** These changes no longer regenerate Docker Compose
configuration, which they do not affect.
2026-09-18 00:23:40 +07:00
Luke Childs 97911c0951 Prevent browser caching of server errors
A temporary failure while serving an asset could return `500
{"error":true}` with the asset route's `public, max-age=31536000,
immutable` header. Chromium could then keep showing a broken machine
icon across page refreshes until the image was force-reloaded.

Override any existing cache policy with `Cache-Control: no-store` in the
shared fallback error handler. Successful asset responses retain their
existing caching. Extract the handler so HTTP regression tests can
exercise it with real Express static-file responses.
2026-09-18 00:21:12 +07:00
Luke Childs 9470ee6d79 Add Omarchy desktop machine template
Adds Omarchy 4.0.4 as an amd64 desktop template, installed unattended
from its checksum-pinned official ISO. Reuses the existing Machines
workflow, cleans up temporary installation media and credentials, and
configures power-off to work from the web UI. Disks are unencrypted so
VMs can boot unattended.
2026-09-17 23:32:51 +07:00
Luke Childs 7c65b02e31 Restore app proxy startup TCP wait
Restore the former app-proxy container’s startup TCP wait: keep proxy
listeners closed until the upstream port accepts connections. Each proxy
waits independently, and removing/restarting an app’s containers repeats
the check. The check only opens a TCP connection, preserving
compatibility with redirects and authentication requirements.

Keep proxy availability independent of app lifecycle state. Already
reachable proxies remain available during boot, and startup hooks can
reach the proxy before the lifecycle command finishes. App states retain
their previous timing and become ready when the existing lifecycle
commands complete. Pending waits are cancelled when the app is stopped
or removed and during ingress shutdown.
2026-09-17 22:58:21 +07:00
Luke Childs c880b18e2f Automatically clean up unused Docker images
Remove Docker images no longer needed by installed apps or umbrelOS,
catching leftovers from restores, failed updates, and skipped versions.
Preserve images required by stopped apps or existing containers, delete
without force, and skip cleanup when the required images cannot be
determined reliably. Unused images pulled manually are also eligible for
removal.

Run cleanup 10 minutes after startup and after app
install/update/uninstall attempts once active operations finish.
Coordinate cleanup with app operations so they cannot overlap.
2026-09-17 22:02:39 +07:00
Nathan Fretz 7342ee3129 Let users rename phone backups in Photos
Users can rename a phone backup in the Photos details panel.

Only the name shown in Photos changes. The folder in Files, backed-up
photos, and upload paths stay unchanged. The new name is retained when
the phone reconnects or umbrelOS restarts, with no iOS app update
needed.

This reuses the existing saved name, Photos database entry, validation,
and locking. No new storage fields or database migration needed.
2026-09-17 22:20:50 +10:00
Luke Childs fcb73178ac Show onboarding notification when upgrading to 2.0 without apps
Add `onboarding-complete` during startup migrations when an installation
upgrades from a pre-2.0 release to 2.0 or later and has no installed
apps. The version check includes 2.0 prereleases and prevents the
notification from returning after dismissal on subsequent boots or 2.x
updates.
2026-09-17 17:35:13 +07:00
Luke Childs 5464842b4f Fix machine image download address fallback
Machine image downloads can fail when the first DNS address is
unreachable, even when another address works. This affected Fedora
installation on a device with unreachable IPv6 and working IPv4.

Preserve all validated DNS addresses and pass the complete list to
Node's automatic address selection, allowing connection attempts to fall
back to IPv4 or another address of the same family. Keep connections
pinned to the validated answers, retain rejection of mixed
public/private DNS results, and repeat validation for each redirect
destination.

Regression tests exercise the full downloader with public DNS fixtures
routed to a local HTTP server. Node makes real TCP connections and
performs the fallback; the tests verify the resulting file contents,
size, SHA-256, and temporary-file cleanup. They cover unreachable IPv6
and IPv4 addresses on both the initial URL and a redirect destination,
plus private-address rejection at both locations.
2026-09-17 16:38:06 +07:00
Nathan Fretz fb31e5ef47 Fix footer overlap and button movement in cloud setup 2026-09-17 13:31:29 +10:00
Nathan Fretz 05fe5dbce3 Keep app update rows visible and button transitions stable
Starting an app update could remove its row from the updates dialog
before the update finished. The backend publishes the new manifest
before pulling images and starting the app, but the update list only
compared versions. An early poll could also report `ready` while the
backend prepared an update, briefly switching buttons from Updating back
to Update and restarting their width animation.

Keep apps visible while their update is pending or running, and show an
animated percentage in the dialog using the existing progress
components. A shared mutation-cache selector gives pending updates
precedence over early ready polls in app detail buttons, official and
community App Store card actions, Update all, and the updates shelf.
Polling continues to supply progress, and each app returns to server
state when its mutation settles.

Keep the shared progress button label visible and animate its background
alongside the progress fill, preserving the existing width animation.
Reuse the existing state readers and update flow without new timers,
state stores, or backend changes.
2026-09-17 13:06:45 +10:00
Nathan Fretz d1e2a220ff Fix App Store release row overlap
Long version labels could push the “Update available” pill and
expand/collapse icon into the release date. On release columns narrower
than 440 px, move only the update pill below the version. Keep the +/−
beside the version and the date aligned right, with the pill inline on
wider columns. Long versions can wrap so their suffix stays readable.
2026-09-17 12:55:12 +10:00
Nathan Fretz 873e1a2cbd Refresh photo details when returning to Photos
Mark cached photo details stale when Photos opens or reconnects so
renames and moves in Files are reflected when a photo is opened.

Opening the thumbnail grid adds no detail requests or thumbnail reloads.
Details refresh when a photo is opened, or immediately if one is already
open on reconnect. Subsequent openings use normal caching.

Cancel older detail requests to prevent late responses from restoring
stale data. Add regression coverage for refresh behavior, cancellation,
and preserving timeline caches.
2026-09-17 12:06:37 +10:00
Nathan Fretz 603b760b9c Fix Files drag-and-drop after opening folders on hover
Fix file drops after opening folders on hover by using the stored drag
selection.

Preserve same-folder checks and correctly handle selections spanning
multiple directories.
2026-09-17 11:22:01 +10:00
Luke Childs b7e92fcca4 Report app update preparation failures correctly
App update scripts could report success and install the new version's
manifest even when preparation failed. Their exit handlers captured an
earlier success status and reused it after errors or interruptions.

Remove those handlers from both update paths so failures and signals
reach the caller and the previous manifest stays installed when
preparation fails. Umbreld stops the update and clears its updating
state and progress through its existing error handling. Successful
preparation still publishes the new manifest for the remaining update
stages.

Files copied before a failure remain installed; this change does not add
rollback or recovery from broken installed files.

Add regression tests for exports and template errors, SIGINT/SIGTERM,
legacy image-pull failures, and successful preparation. The shell tests
run the real script with Docker stubbed. A lifecycle test verifies that
a preparation error prevents compose patching and image pulls and clears
update state and progress.
2026-09-17 03:01:53 +07:00
Luke Childs c7f1a7107b Prevent concurrent app operations from corrupting exports
Concurrent app operations can corrupt an installed `exports.sh` when
dependency sourcing rewrites it while an update overwrites it in place.
This can leave empty, partial, or stale exports and break dependent
apps.

Source a transformed temporary copy beside the original, preserving
legacy path substitutions and source-relative directory resolution.
Publish top-level package files by copying to a temporary file and
renaming it into place after the copy succeeds. Readers retain complete
old files or see complete replacements, with file metadata preserved.

Clean up temporary files on exit, errors, and handled signals. Track
ownership per shell so subshells cannot remove their parent's active
source file. Preserve existing trap syntax, exit statuses, and ignored
signals, including empty handlers and handlers containing comments or
trailing semicolons.

Add shell regression tests covering file integrity, compatibility,
metadata, failed copies and renames, temporary-file cleanup, and
existing trap behavior. The tests run the real app script and hold
readers open across updates to verify that the original bytes survive
replacement.
2026-09-17 02:50:00 +07:00
Luke Childs 6ab90dd3fd Restart Watchman when file-watcher health checks fail
Failed file-watcher health checks currently reconnect to the same
Watchman daemon and request a full index scan even when recovery fails.
Restart the daemon when event delivery stops or Watchman reports poison,
verify Home event delivery before requesting a catch-up scan, and retry
unavailable folders without interrupting healthy watches.

## Behavior

- A missed sentinel or explicit Watchman poison error tears down
subscriptions, stops the daemon, and recreates watches. Ignore callbacks
from retired subscriptions and sentinel deletion events when verifying
recovery.
- Retry missing subscriptions individually on the existing five-minute
health-check schedule, including when no subscriptions started. A
missing or inaccessible folder does not repeatedly restart healthy
watches. A successfully restored folder requests one catch-up scan after
Home event delivery is verified; another unavailable folder does not
block that catch-up.
- Stop Watchman with `--no-spawn --no-local` and a five-second command
timeout. Accept an already absent daemon, check the shutdown
confirmation, and report command failures instead of treating them as
successful recovery.
- Keep one health check in flight. Shutdown cancels pending sentinel
checks and prevents recovery from creating replacement subscriptions
after stopping begins. Roots added during recovery are included in setup
or retried independently.
- Preserve the index's independent periodic reconciliation. Failed
event-delivery recovery does not request repeated additional scans.
- Make Samba's deletion, rename, and parent-deletion tests wait for
persisted share cleanup with a five-second deadline instead of assuming
asynchronous watcher delivery and store writes finish within 100 ms.
2026-09-17 02:18:22 +07:00
Luke Childs 0b9f6f4864 Speed up Photos library reads and refreshes
Photos refreshes repeatedly reconstructed the library across all indexed
files, occupying the file-index worker that also serves media requests.
Persist the derived library and indexing-status counts, use indexed
lookups for small sources, and coalesce UI refreshes so routine reads do
less work.

On a 35,000-item library, measured summary-query time fell from **13
seconds to 78 milliseconds (about 167× faster)**.

## Changes

- Store authorized file locations, Live Photo relationships, and visible
library items in disposable `index.db` tables. Favorites, albums, source
permissions, and backup identities remain durable in `umbrel.db`.
- Index timeline/filter queries, count matches separately from page
hydration, and use source-membership indexes for source-only filters
with at most 1,000 candidate hashes. Read summaries and albums from the
stored library and maintain per-account indexing-status counters.
- Update changed content and its old/current Live Photo dependencies
transactionally. Persistent change journals and paired generation
markers recover missed callbacks and interrupted commits across the two
databases while preserving account isolation.
- Refresh the UI from account-scoped Photos events. Wait for existing
reads, preserve events received during that wait, and combine them into
one follow-up refresh. Refetch shallow timelines, mark deep timelines
stale, and cancel scheduled refreshes when Photos closes.
- Read source names by ID instead of storing duplicate names in library
rows, so renaming a source does not rebuild the account. Use the same
32,768-hash full-refresh cutoff at startup and during reads; 128 remains
the incremental batch size.
- Resolve destination identity and metadata before completing Photos
moves, including when a watcher has already removed the source entry.
This makes immediate Trash lookup and restore reliable.

**CI status:** the Samba multi-user VM check is red, but its latest
`STATUS_PENDING` failure is a confirmed pre-existing test-client issue:
the same test and stack failed on staging, without these Photos changes.
The SMB test client incorrectly rejects a valid interim response; an
isolated parser probe reproduces that behavior. The original
connection-reset case passed on rerun, although that reset's cause has
not been isolated.
2026-09-17 00:33:39 +07:00
Nathan Fretz f8dcdcba6b Preserve native app TLS with explicit hostname routing
LAN ingress presents Umbrel’s certificate on app browser ports, breaking
native clients such as Plex’s `plex.direct:32400` connections that
expect the app’s own certificate.

Apps serving HTTP and TLS on the same port can opt in through their
installed manifest with nativeTlsHostnameSuffixes.

Matching SNI names pass through encrypted to the app’s fixed loopback
port. HTTP, Umbrel names, unknown SNI and absent SNI retain their
existing routes. Suffixes match complete DNS labels at any depth.
Packaged `app_proxy` services remain excluded even when gateway
authentication is disabled; invalid metadata leaves the existing route
intact.

The reader handles fragmented ClientHellos and preserves the original
bytes, with connection, memory and time limits. Policy changes close
affected connections; normal socket closure flushes queued writes.
2026-09-16 23:12:16 +10:00
Luke Childs 2f760ae475 Stop recursively indexing and watching app data
App data can contain millions of rapidly changing runtime files, such as
Portainer's Docker `overlay2` tree. Recursively indexing and watching
that tree can exhaust Watchman and trigger repeated reconciliation work
that also affects normal Files use. Exclude `/Apps` from recursive scans
and watches while preserving browsing, on-demand thumbnails, sharing,
and live app disk-usage reporting.

## Behavior and transition

- **Stop recursively indexing and watching app data.** Mark `/Apps` as a
non-scanned root. File metadata still comes from disk, and explicitly
requested thumbnails use transient index entries. Folder sizes in Files
remain unknown without an indexed aggregate.
- **Remove old index entries once.** Migration 17 deletes the crawled
`/Apps` root and its dependent entries, including FTS and thumbnail
records. Other roots and shared content remain intact; existing asset
maintenance reclaims orphaned content. Later boots preserve new
transient thumbnail entries. No database vacuum is forced.
- **Use existing OS reboot behavior for Watchman.** Watchman state is
outside umbrelOS's persisted directories, so the update reboot clears
the old app watch. Startup does not run special watch-retirement
commands. Broader runtime recovery remains tracked in #1531.
- **Clean up saved references directly.** Files move, rename, trash, and
delete operations remove affected app favorites, Samba shares, and
member shares. Copy/move replacement and Trash restore also clean up the
destination before writing replacement content. App uninstall removes
references to `/Apps/<app-id>` and its descendants before deleting app
data. Cleanup checks saved reference lists without crawling directories;
similarly named sibling paths are preserved.
- **Check external changes at startup and daily.** Monitor only
explicitly favorited or shared app directories every 24 hours. Missing
directories and identity changes observed during the process lifetime
remove stale references. Identities remain in memory: replacement across
an umbreld restart can still be missed. App uninstall cleanup handles
the normal uninstall/reinstall case directly.
- **Refresh app browsing.** Poll the visible `/Apps` directory listing
every five seconds. Favorites and member-share lists retain their
existing mutation, remount, visibility, and reconnect refreshes; members
also receive share-change events. Idle favorites and owner-share views
may remain stale until a refresh trigger. No new list polls are added
for those views.
- **Restore live app disk usage.** Restore the behavior before [PR
#1448](https://github.com/getumbrel/private-umbrel/pull/1448): measure
with `du` on each request, retry failures twice, and report zero for a
location that remains unavailable. Retain independent measurements for
relocated external app data. Remove the unused Files directory-size
helper.
2026-09-16 18:53:15 +07:00
Mayank Chhabra cad1e5453a UI improvements and fixes
- Keep disconnected network hosts and shares visible and removable.
- Refresh network availability through backend events and polling.
- Disable unavailable share actions and restore capabilities on reconnect.
- Prevent member views from using cached owner network configuration.
- Unify uploads, copies, and moves in a shared queue and Transfers island.
- Add batch progress, conflict resolution, retries, and cancellation controls.
- Limit transfer concurrency while keeping same-device moves responsive.
- Keep file listings synchronized with upload and move progress.
- Preserve transfers across navigation, clear them on sign-out, and warn
  before leaving with browser-dependent work pending.
- Track custom VM image uploads by transfer ID and open their final path,
  including files renamed by "Keep both".
- Keep machine names stable while creation updates the live machine list.
- Keep RAID setup polling through Safari and Firefox transport errors
  while still reporting backend failures.
- Focus the What's New dialog when it opens.
- Add regression tests for transfers, network storage, directory listings,
  and transport error handling.
2026-09-16 16:29:10 +07:00
Mayank Chhabra 7667ee8bd2 Redesigned Cmd+K search
Rebuild the command palette around a wallpaper-colored animated orb and
a glass surface that adapts to its results.

- Search everywhere or narrow to Files, Photos, App Store and Settings,
  with Tab and Shift+Tab cycling scopes.
- Rank results and sections by match quality, combining command rows
  with app, file and photo tiles. Open photos directly in the lightbox
  or continue a search in its app.
- Navigate rows and grids with the keyboard, preserve user selection
  as results arrive, and keep the active result visible and accessible.
- Retain the query and scope between opens. Select the query on reopen;
  Escape clears it before closing.
- Keep typing responsive with memoized entries and deferred App Store
  search. Refresh server results on reopen and pause searches when closed.
- Support search handoffs into Photos and App Store, including when
  already open, while preserving shared query-cache behavior.

The orb responds to typing and falls back to a matching CSS gradient
when WebGL is unavailable.
2026-09-16 14:10:41 +07:00