fix: overhaul container lifecycle — recovery, health, uninstall, UI state
Container recovery: - Health monitor: MAX_RESTART_ATTEMPTS 3→10, interval 60s→120s - Dependency-aware restarts: won't restart services before their deps - Reset dependent counters when a dependency recovers - Handle "created" state containers (were invisible to health monitor) - Added IndeedHub, mempool-api, mysql to tier system - Crash recovery: podman start timeout 30s→120s with retry - Podman client: socket timeout 5s→30s, added restart policy UI state representation: - Exit code 0 shows "stopped" (gray), not "crashed" (red) - Exit code 137 shows "killed (OOM)" - Non-zero exit shows "crashed" (red) - Added exit_code field to PackageDataEntry Install/uninstall fixes: - Install returns error when container doesn't start (was silent success) - Post-install hooks awaited instead of fire-and-forget tokio::spawn - Uninstall: graceful rm before force, volume prune, network cleanup - Uninstall returns error on partial failure (was 200 OK) Config consistency: - DB passwords read from /var/lib/archipelago/secrets/ (was hardcoded) - Bitcoin: added ZMQ ports 28332/28333 for LND block notifications - IndeedHub port 7777→8190 (was conflicting with strfry) - Marketplace versions: LND 0.17.4→0.18.4, Mempool 2.5.0→3.0.0 Performance: - Metrics collector interval 60s→300s (was duplicating health monitor) - Podman client: proper error propagation instead of unwrap_or_default Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
cdff10a8bc
commit
64b57dca7d
@@ -2,9 +2,9 @@
|
||||
<!-- Persistent Mobile Tabs for Apps/Marketplace -->
|
||||
<div
|
||||
v-if="showAppsTabs && !isAppSessionActive"
|
||||
class="md:hidden fixed top-0 left-0 right-0 z-40 px-4 pt-4 pb-2 glass-piece"
|
||||
class="md:hidden fixed top-0 left-0 right-0 z-40 px-4 pb-2 glass-piece mobile-top-tabs"
|
||||
:class="{ 'glass-throw-mobile-tabs': showZoomIn }"
|
||||
style="background: rgba(0, 0, 0, 0.25); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); transform: translateZ(0);"
|
||||
style="background: rgba(0, 0, 0, 0.25); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); transform: translateZ(0); padding-top: calc(var(--safe-area-top, env(safe-area-inset-top, 0px)) + 16px);"
|
||||
>
|
||||
<div class="mode-switcher mode-switcher-full">
|
||||
<RouterLink
|
||||
@@ -29,10 +29,10 @@
|
||||
<!-- Persistent Mobile Tabs for Network/Cloud -->
|
||||
<div
|
||||
v-if="showNetworkTabs && !isAppSessionActive"
|
||||
class="md:hidden fixed top-0 left-0 right-0 z-40 px-4 pt-4 pb-2 glass-piece"
|
||||
class="md:hidden fixed left-0 right-0 z-40 px-4 pb-2 glass-piece mobile-top-tabs"
|
||||
:class="{ 'glass-throw-mobile-tabs-2': showZoomIn }"
|
||||
style="background: rgba(0, 0, 0, 0.25); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); transform: translateZ(0);"
|
||||
:style="{ top: showAppsTabs ? '80px' : '0' }"
|
||||
:style="{ top: showAppsTabs ? '80px' : '0', paddingTop: showAppsTabs ? '16px' : 'calc(var(--safe-area-top, env(safe-area-inset-top, 0px)) + 16px)' }"
|
||||
>
|
||||
<div class="mode-switcher mode-switcher-full">
|
||||
<RouterLink
|
||||
@@ -66,7 +66,7 @@
|
||||
:aria-label="t('dashboard.mobileNav')"
|
||||
class="md:hidden fixed bottom-0 left-0 right-0 border-t border-glass-border shadow-glass z-50 glass-piece"
|
||||
:class="{ 'glass-throw-tabbar': showZoomIn }"
|
||||
style="background: rgba(0, 0, 0, 0.25); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); padding-bottom: env(safe-area-inset-bottom, 0px);"
|
||||
style="background: rgba(0, 0, 0, 0.25); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); padding-bottom: var(--safe-area-bottom, env(safe-area-inset-bottom, 0px));"
|
||||
>
|
||||
<div class="flex justify-around items-center px-2 py-3 relative">
|
||||
<RouterLink
|
||||
@@ -160,11 +160,21 @@ const showNetworkTabs = computed(() => {
|
||||
return route.path.includes('/server') || route.path.includes('/cloud') || route.path.includes('/web5') || route.path.includes('/mesh')
|
||||
})
|
||||
|
||||
// Top padding for content div to clear fixed mobile tab overlays
|
||||
// Top padding for content div to clear fixed mobile tab overlays.
|
||||
// Includes safe area inset for Android (read from CSS custom property set by WebView).
|
||||
const safeAreaTop = ref(0)
|
||||
|
||||
function readSafeAreaTop() {
|
||||
if (typeof window === 'undefined') return
|
||||
const val = getComputedStyle(document.documentElement).getPropertyValue('--safe-area-top').trim()
|
||||
if (val) safeAreaTop.value = parseInt(val, 10) || 0
|
||||
}
|
||||
|
||||
const mobileTabPaddingTop = computed(() => {
|
||||
if (typeof window === 'undefined' || window.innerWidth >= 768) return 0
|
||||
if (showAppsTabs.value && showNetworkTabs.value) return 160
|
||||
if (showAppsTabs.value || showNetworkTabs.value) return 80
|
||||
const sat = safeAreaTop.value
|
||||
if (showAppsTabs.value && showNetworkTabs.value) return 160 + sat
|
||||
if (showAppsTabs.value || showNetworkTabs.value) return 80 + sat
|
||||
return 0
|
||||
})
|
||||
|
||||
@@ -188,7 +198,10 @@ function onResize() {
|
||||
|
||||
onMounted(() => {
|
||||
updateTabBarHeight()
|
||||
readSafeAreaTop()
|
||||
window.addEventListener('resize', onResize)
|
||||
// Re-read after WebView injection has had time to run
|
||||
setTimeout(readSafeAreaTop, 500)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="healthNotifications.length > 0"
|
||||
class="fixed top-4 right-4 z-[200] flex flex-col gap-2 max-w-sm"
|
||||
class="fixed right-4 z-[200] flex flex-col gap-2 max-w-sm"
|
||||
style="top: calc(var(--safe-area-top, env(safe-area-inset-top, 0px)) + 16px);"
|
||||
>
|
||||
<div
|
||||
v-for="notif in healthNotifications"
|
||||
|
||||
Reference in New Issue
Block a user