feat: registry health indicator
Show colored dot next to each registry name: - Yellow (pulsing): checking connectivity - Green: connected and reachable - Red: unreachable or auth failed Health is checked automatically when the registries page loads and updated when "Test Connection" is clicked.
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
let formOwner = $state('');
|
let formOwner = $state('');
|
||||||
let formSaving = $state(false);
|
let formSaving = $state(false);
|
||||||
let testingId = $state<string | null>(null);
|
let testingId = $state<string | null>(null);
|
||||||
|
let healthStatus = $state<Record<string, 'checking' | 'healthy' | 'unhealthy'>>({});
|
||||||
|
|
||||||
let errors = $state<Record<string, string>>({});
|
let errors = $state<Record<string, string>>({});
|
||||||
|
|
||||||
@@ -37,7 +38,11 @@
|
|||||||
|
|
||||||
async function loadRegistryList() {
|
async function loadRegistryList() {
|
||||||
loading = true;
|
loading = true;
|
||||||
try { registries = await listRegistries(); } catch (err) { toasts.error(err instanceof Error ? err.message : $t('settingsRegistries.loadFailed')); } finally { loading = false; }
|
try {
|
||||||
|
registries = await listRegistries();
|
||||||
|
// Check health of all registries in the background.
|
||||||
|
checkAllHealth();
|
||||||
|
} catch (err) { toasts.error(err instanceof Error ? err.message : $t('settingsRegistries.loadFailed')); } finally { loading = false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleSave() {
|
async function handleSave() {
|
||||||
@@ -61,9 +66,26 @@
|
|||||||
|
|
||||||
async function handleTestConnection(registry: Registry) {
|
async function handleTestConnection(registry: Registry) {
|
||||||
testingId = registry.id;
|
testingId = registry.id;
|
||||||
try { await testRegistry(registry.id); toasts.success($t('settingsRegistries.testSuccess', { name: registry.name })); }
|
try {
|
||||||
catch (err) { toasts.error(err instanceof Error ? err.message : $t('settingsRegistries.testFailed')); }
|
await testRegistry(registry.id);
|
||||||
finally { testingId = null; }
|
toasts.success($t('settingsRegistries.testSuccess', { name: registry.name }));
|
||||||
|
healthStatus[registry.id] = 'healthy';
|
||||||
|
} catch (err) {
|
||||||
|
toasts.error(err instanceof Error ? err.message : $t('settingsRegistries.testFailed'));
|
||||||
|
healthStatus[registry.id] = 'unhealthy';
|
||||||
|
} finally { testingId = null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkAllHealth() {
|
||||||
|
for (const reg of registries) {
|
||||||
|
healthStatus[reg.id] = 'checking';
|
||||||
|
try {
|
||||||
|
await testRegistry(reg.id);
|
||||||
|
healthStatus[reg.id] = 'healthy';
|
||||||
|
} catch {
|
||||||
|
healthStatus[reg.id] = 'unhealthy';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$effect(() => { loadRegistryList(); });
|
$effect(() => { loadRegistryList(); });
|
||||||
@@ -134,6 +156,13 @@
|
|||||||
<div class="flex items-center justify-between rounded-xl border border-[var(--border-primary)] bg-[var(--surface-card)] p-4 shadow-[var(--shadow-sm)] transition-all duration-150 hover:shadow-[var(--shadow-md)]">
|
<div class="flex items-center justify-between rounded-xl border border-[var(--border-primary)] bg-[var(--surface-card)] p-4 shadow-[var(--shadow-sm)] transition-all duration-150 hover:shadow-[var(--shadow-md)]">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
|
{#if healthStatus[registry.id] === 'checking'}
|
||||||
|
<span class="h-2.5 w-2.5 shrink-0 rounded-full bg-yellow-400 animate-pulse" title="Checking..."></span>
|
||||||
|
{:else if healthStatus[registry.id] === 'healthy'}
|
||||||
|
<span class="h-2.5 w-2.5 shrink-0 rounded-full bg-emerald-500" title="Connected"></span>
|
||||||
|
{:else if healthStatus[registry.id] === 'unhealthy'}
|
||||||
|
<span class="h-2.5 w-2.5 shrink-0 rounded-full bg-red-500" title="Unreachable"></span>
|
||||||
|
{/if}
|
||||||
<h3 class="text-sm font-semibold text-[var(--text-primary)]">{registry.name}</h3>
|
<h3 class="text-sm font-semibold text-[var(--text-primary)]">{registry.name}</h3>
|
||||||
<span class="rounded-full bg-[var(--surface-card-hover)] px-2 py-0.5 text-xs font-medium text-[var(--text-tertiary)]">{registry.type}</span>
|
<span class="rounded-full bg-[var(--surface-card-hover)] px-2 py-0.5 text-xs font-medium text-[var(--text-tertiary)]">{registry.type}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user