Load the compose file only after the user confirms its location, initialize the default compose path when switching build packs, and retain existing application domains.
Resolve custom container names consistently, clean up legacy container names during deployments, and route Livewire resource redirects through the navigation helper.
Use stable identities for dynamic rows and nested components so reordering does not target the wrong item. Scope storage count and volume-list refreshes, preserve PostgreSQL script identity when renaming files, use Livewire-aware destination redirects, and bump the version to 4.3.13.
Address review feedback and UX issues on the file browser.
Editor
- Replace the TipTap editor with Monaco, reusing the self-hosted assets. The
editor is kept mounted (wire:ignore) and preloaded on page init, and receives
content + language via the load-file-editor event, applying the language with
setModelLanguage so highlighting is correct without recreating the instance.
- Keep the Monaco instance on the DOM node, not in Alpine reactive state, so its
object graph is never proxied (that hung and crashed the tab).
- Drop @tiptap/*, lowlight and highlight.js; remove the TipTap CSS and JS.
- Broaden guessLanguage to Monaco ids and common extension-less/dotfiles.
Listing / read (perf)
- List a directory in one stat call instead of a per-entry loop (embedding a
real tab, since stat -c does not expand \t), and surface owner/group columns.
- Fold the read size-cap, binary probe and base64 into one SSH round trip.
Actions
- Collapse the per-row Edit/Download/Rename/Delete buttons into a 3-dots menu.
- Fix actions silently failing on names with apostrophes: the entry name now
lives in the row's Alpine scope instead of passing @js() through a component
attribute (which double-encodes the quotes).
Hardening
- Lock client-controllable state (container/type/resource) with #[Locked].
- Re-check guard() in open/goTo/refresh; sanitize upload filenames; clean up the
download temp file and report errors; route >96KiB writes through docker cp.
Tests updated and extended (32 passing). Frontend rebuild (npm run build) is
still needed only to drop TipTap from the bundle; the editor works without it.
- Escape dynamic file/path names with @js() in Livewire click handlers
instead of interpolating raw strings, and lock resource/container
properties to prevent client-side property tampering
- Route writes over ~96 KiB through docker cp instead of an inline
base64 shell argument, which was capped by MAX_ARG_STRLEN
- Treat empty files as editable text instead of misclassifying them
as binary