Address review findings on the fleet metrics page.
Data correctness:
- bucket raw Sentinel samples into epoch-aligned windows (5m/30m/2h per range)
and average them, replacing per-server LTTB. Every server now reports the
same bucket timestamps, so the fleet sums add up point by point instead of
zigzagging between servers (and RX+TX really combine)
- keep only the root mount in disk history, matching HasMetrics::getDiskMetrics
- leave sparkline gaps as null instead of 0, so absent samples read as gaps
Robustness:
- normalize containerMetric in mount()/updatedContainerMetric(), so
/metrics?cmetric=foo no longer throws an undefined array key
- include the server uuid in the container row wire:key; system containers
share one Sentinel id across servers
- round the range start to the minute so the 60s history cache can hit
- cap the Sentinel curl with --max-time 10, so one hung request cannot stall
the serial per-server loop
UI:
- pass the spark time axis on first paint, so tooltips no longer show 1970
- show the active series name (RX/TX) in the server network chart tooltip
Refine the /metrics fleet page and align the per-server metrics page with it.
Fleet overview:
- add live sparklines to the CPU/Memory/Disk/Network KPI tiles (shared axis,
capped to ~40 points per sparkline)
- fill the Servers online + Containers tiles (fleet-health bar, hottest
container) so all six tiles read as one system
- scope-aware labels: drop the "Fleet" prefix and helper copy when a single
server is selected
Trend charts:
- hero layout: CPU spans full width, the other four form a 2x2 grid
- apply the same hero layout + skeleton to the per-server page for consistency
Hottest containers table:
- add a rank column and a per-row magnitude bar scaled to the busiest container
- fix a leaked Blade @break directive that rendered literally and forced
horizontal scroll on the Network tab
- keep the value column a fixed width so bars align across rows
Live refresh:
- add analytics-style loading feedback to the range tabs and server filter
- stable wire:key on table rows + width transitions on bars so data glides
on live refresh instead of snapping
Generalize the shared _sparkline partial (optional color/label/format) so it
serves non-traffic metrics without changing analytics behaviour.
API log endpoints and the GetLogs UI now treat `all` as unbounded
output, with `-1` remaining as a compatibility alias. MCP still
falls back to a positive default. Traefik version checks run from
CheckForUpdatesJob instead of a weekly schedule.
Cache the related database before deleting the backup so authorization,
server lookup, and the service redirect do not touch a deleted morph.
Skip rendering after delete and cover the service-database path.
Move service application and database settings into an embedded modal with a footer, subtitle helper, and Docker restart-count control. Accept max_restart_count on the service applications API, cap compose YAML collection aliases, and tighten status, backup, and database sidebar layouts.
S3-compatible and legacy buckets may include uppercase letters. Relax the bucket name pattern, validation messages, and tests so those names are accepted while still rejecting invalid characters and formats.
Add indexing, redirect, and hostname regeneration controls to domain editors. Queue DNS checks only for scheme or hostname changes and show progress consistently across application, service, and preview domains.
Add restartLimitReached to the notification event toggle list so admins can disable restart-limit email notifications. Cover the toggle with an authorization test.
Pull image-based Docker Compose services with --ignore-buildable before stopping the current deployment so image-only services are ready first. Fail the deploy if pull fails, and run the pull on the runtime server when a build server is used.
Pass S3 endpoint and keys as helper container env vars and run mc alias
via those variables so the stored import command no longer contains
access keys or secrets. Start the helper in a separate remote process,
use the storage filesystem adapter for object checks, and remove a
credential temp file during import cleanup when the path is safe.
Move database import temp/container cleanup into a queued listener with retries, and clear the import running state on failed restore starts. Tighten Cloudflare replace/delete to the current server IP and owning resource, notify when DNS jobs fail, and pass domain-removal confirmation through remove-by-key. Document import request oneOf schemas without extra properties.
Single-database mysql/mariadb imports accepted .gz files but redirected
them straight into the client. Pipe through the existing gunzip fallback
used by dump-all restores.
Hold a cache lock keyed by database UUID across the active-import
check and remote_process so two concurrent requests cannot both
queue a restore against the same database.
ConfigureDnsRecordJob requires a string content value. Guard
configureDnsAfterDomainAdd with the same blank and FILTER_VALIDATE_IP
checks used by createManagedDnsRecord so a missing or hostname-only
server address cannot TypeError after the domain is saved.
Allow single-database PostgreSQL imports to drop matching objects before restore. The API and import form accept replace_existing, which adds --clean --if-exists to pg_restore, and pg_restore now uses --exit-on-error.