* fix(dataTable): resizing a column no longer squashes the others
mantine-datatable's built-in column resize keeps the table's total
width fixed by shrinking every other column to compensate, which
collapses columns toward zero in a narrow widget (open upstream
issue, no fix: icflorescu/mantine-datatable#discussions-757).
Replaced it with our own resize handle that only ever changes the
width of the column being dragged - the table grows and scrolls
horizontally instead. Shared via usePersistedTableLayout, so docker,
downloads, and beszel-system-table all get it.
* feat(docker): enable hold-Shift advanced focus preview
The widget already renders differently for displayMode="advanced",
but was missing supportsAdvancedFocus: true, so the board never
offered the hold-Shift preview for it - matching downloads and
media-server, which both set this flag.
* style(docker): tighten row density, decouple icon size from row height
Circular avatar, denser row/footer padding, and action icons rendered
larger than their button via absolute positioning so they don't
inflate row height (the button stays small and fixed - it repeats
once per row, so any growth there multiplies across every visible
container).
* fix(data-table): harden shared column resizing
* fix(data-table): account for board scaling
* fix(data-table): compact shared headers
* fix(data-table): fit columns to widget
* fix(downloads): simplify advanced details
* test(widgets): align Docker advanced focus
* fix(downloads): widen expanded details
---------
Co-authored-by: ajnart <thomas@ajnart.dev>
Board scaling: no sideways scrolling
- Revert the pannable narrow canvas. The canvas fits the viewport again and
`.viewport` goes back to `overflow: clip`, so a board can never widen the
document or scroll horizontally.
- Fix the unreadable-narrow-board regression at the real cause instead: cap the
inverse UI compensation at 2x (50% canvas scale). Down to 50% text and
controls keep their physical size; below it the board zooms out as a whole, so
a 200x200 logical tile hosts at most 28px logical text rather than 96px and
content stops overlapping its neighbours.
Touch editing
- Add `touch-action: none` to `.board-grid-entry`, the dnd-kit draggable and its
own drag handle. The 200ms touch activation delay is useless if the browser
has already handed the gesture to page panning and emitted `pointercancel`.
Only edit mode renders this element.
Custom widgets
- Memoize the merged `data`/`status`/`options` passed to `CustomJsxRenderer`.
They were rebuilt every render, so the compiled-template memo never hit and
the new reference-identity boundary key changed on every render, resetting the
error boundary and forcing an extra reconciliation of the widget subtree.
- Keep the cache key when the shared Redis cache is unavailable so the
process-local cache still absorbs polling instead of sending every widget
refresh upstream.
- Reclaim the shared cache's LRU/size/byte bookkeeping for TTL-expired entries
and touch the LRU in the same script, so expired ghosts stop consuming the
64 MiB budget and a read costs one round trip instead of two.
Forwarded IP
- Restore `ipAddressFromHeaders` to the full forwarding chain and add
`trustedIpAddressFromHeaders` for the last hop. Repointing the shared helper
had collapsed MCP failed-auth rate limiting into a single bucket for every
client behind a reverse proxy and replaced the client IP with the proxy IP in
API-key auth logs.
Runtime and restore
- Make the new /appdata ownership migration best-effort. Under `set -e` a mount
that rejects chown (CIFS/SMB, fixed-uid NFS) turned into a container that
refuses to start, and /appdata was never chowned before.
- Report malformed metadata.json as such instead of blaming the archive.
The compact view auto-reveals name/change/range as the widget gets
bigger, which can overlap badly depending on how the widget's actual
proportions land relative to those breakpoints. Add a switch (on by
default, matching current behavior) to force the minimal symbol+price
look regardless of size. Scoped to the compact layout only - the
Shift-triggered advanced view is untouched.
- Classify IPv4/IPv6 link-local addresses (169.254.0.0/16, fe80::/10) as
LAN in Jellyfin location parsing - they can't traverse a router, so a
false WAN reading was possible for common autoconfig/link-local sessions.
- Fix portrait video resolution mislabeling - a 1080x1920 clip was
classified off its long-axis height (1920) and showed as 1440p. Classify
by the short axis instead so orientation doesn't flip the result.
- Raise the compact-mode status column breakpoint from 420 to 540px - at
420 the fixed-width user (200px) and status (190px) columns left almost
no room for the currentlyPlaying column, the widget's primary content.
- Document the new resolution indicator in the media-server widget docs.