fix: Docker health indicator shows immediately after login
Use $effect instead of onMount to start SSE and health polling, so they activate on client-side navigation after login without requiring a full page reload.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '../app.css';
|
import '../app.css';
|
||||||
import type { Snippet } from 'svelte';
|
import type { Snippet } from 'svelte';
|
||||||
import { onMount, onDestroy } from 'svelte';
|
import { onDestroy } from 'svelte';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import Toast from '$lib/components/Toast.svelte';
|
import Toast from '$lib/components/Toast.svelte';
|
||||||
import ThemeToggle from '$lib/components/ThemeToggle.svelte';
|
import ThemeToggle from '$lib/components/ThemeToggle.svelte';
|
||||||
@@ -37,6 +37,7 @@
|
|||||||
let sseConnection: SSEConnection | null = null;
|
let sseConnection: SSEConnection | null = null;
|
||||||
let sidebarOpen = $state(false);
|
let sidebarOpen = $state(false);
|
||||||
let dockerConnected = $state<boolean | null>(null);
|
let dockerConnected = $state<boolean | null>(null);
|
||||||
|
let healthChecked = $state(false);
|
||||||
let healthInterval: ReturnType<typeof setInterval> | null = null;
|
let healthInterval: ReturnType<typeof setInterval> | null = null;
|
||||||
|
|
||||||
// Hide sidebar and chrome on the login page.
|
// Hide sidebar and chrome on the login page.
|
||||||
@@ -69,29 +70,35 @@
|
|||||||
window.location.href = '/login';
|
window.location.href = '/login';
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
// Start SSE and health polling when authenticated.
|
||||||
if (isAuthenticated()) {
|
// Uses $effect to react to route changes (e.g., after login navigation).
|
||||||
sseConnection = connectGlobalEvents({
|
$effect(() => {
|
||||||
onInstanceStatus(payload) {
|
// Read pathname to re-run on navigation.
|
||||||
instanceStatusStore.update(payload);
|
void $page.url.pathname;
|
||||||
},
|
|
||||||
onDeployStatus(payload) {
|
|
||||||
instanceStatusStore.notifyDeploy(payload);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Poll Docker health every 30s.
|
if (!isAuthenticated() || sseConnection) return;
|
||||||
async function checkHealth() {
|
|
||||||
try {
|
sseConnection = connectGlobalEvents({
|
||||||
const h = await api.getHealth();
|
onInstanceStatus(payload) {
|
||||||
dockerConnected = h.docker;
|
instanceStatusStore.update(payload);
|
||||||
} catch {
|
},
|
||||||
dockerConnected = null;
|
onDeployStatus(payload) {
|
||||||
}
|
instanceStatusStore.notifyDeploy(payload);
|
||||||
}
|
}
|
||||||
checkHealth();
|
});
|
||||||
healthInterval = setInterval(checkHealth, 30_000);
|
|
||||||
|
// Poll Docker health every 30s.
|
||||||
|
async function checkHealth() {
|
||||||
|
try {
|
||||||
|
const h = await api.getHealth();
|
||||||
|
dockerConnected = h.docker;
|
||||||
|
} catch {
|
||||||
|
dockerConnected = false;
|
||||||
|
}
|
||||||
|
healthChecked = true;
|
||||||
}
|
}
|
||||||
|
checkHealth();
|
||||||
|
healthInterval = setInterval(checkHealth, 30_000);
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
@@ -173,7 +180,7 @@
|
|||||||
|
|
||||||
<!-- Footer controls -->
|
<!-- Footer controls -->
|
||||||
<div class="space-y-3 border-t border-[var(--border-primary)] px-4 py-3">
|
<div class="space-y-3 border-t border-[var(--border-primary)] px-4 py-3">
|
||||||
{#if dockerConnected !== null}
|
{#if healthChecked}
|
||||||
<div class="flex items-center gap-2 rounded-md px-2 py-1.5 text-xs {dockerConnected ? 'text-emerald-600' : 'text-red-500'}">
|
<div class="flex items-center gap-2 rounded-md px-2 py-1.5 text-xs {dockerConnected ? 'text-emerald-600' : 'text-red-500'}">
|
||||||
<span class="relative flex h-2 w-2">
|
<span class="relative flex h-2 w-2">
|
||||||
{#if dockerConnected}
|
{#if dockerConnected}
|
||||||
|
|||||||
Reference in New Issue
Block a user