feat(observability): phases 4-7 - complete frontend UI (big bang)
Add all frontend pages for observability & proxy management: - Proxy Viewer: /proxies with grouped view, filtering, health indicators - Proxy Creation: form with live validation, diagnostic hints, edit/delete - Stale Containers: /containers/stale with dashboard widget, cleanup actions - Event Log: /events with filters, pagination, real-time SSE streaming - Navigation: proxies and events links in sidebar - i18n: full EN/RU translations for all new features - Settings: stale threshold configuration
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
<!--
|
||||
Phase 6: Validation checklist for proxy destination validation.
|
||||
Shows each validation step with pass/fail/pending status indicators.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { ValidationResult } from '$lib/types';
|
||||
import { IconCheck, IconX, IconLoader } from '$lib/components/icons';
|
||||
import { t } from '$lib/i18n';
|
||||
|
||||
interface Props {
|
||||
result: ValidationResult | null;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
const { result, loading = false }: Props = $props();
|
||||
|
||||
/** Map step names to i18n keys. */
|
||||
const stepLabelKeys: Record<string, string> = {
|
||||
syntax: 'proxies.validation.syntax',
|
||||
dns: 'proxies.validation.dns',
|
||||
tcp: 'proxies.validation.tcp',
|
||||
http: 'proxies.validation.http'
|
||||
};
|
||||
|
||||
function getStepLabel(name: string): string {
|
||||
const key = stepLabelKeys[name];
|
||||
return key ? $t(key) : name;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if loading || result}
|
||||
<div class="rounded-lg border border-[var(--border-primary)] bg-[var(--surface-card)] p-4">
|
||||
<h4 class="text-sm font-medium text-[var(--text-primary)] mb-3">
|
||||
{$t('proxies.validation.title')}
|
||||
</h4>
|
||||
|
||||
{#if loading && !result}
|
||||
<div class="flex items-center gap-2 text-sm text-[var(--text-secondary)]">
|
||||
<IconLoader size={16} />
|
||||
<span>{$t('proxies.validation.checking')}</span>
|
||||
</div>
|
||||
{:else if result}
|
||||
<ul class="space-y-2">
|
||||
{#each result.steps as step}
|
||||
<li>
|
||||
<div class="flex items-center gap-2">
|
||||
{#if step.passed}
|
||||
<span class="flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full bg-emerald-100 dark:bg-emerald-950">
|
||||
<IconCheck size={14} class="text-emerald-600 dark:text-emerald-400" />
|
||||
</span>
|
||||
<span class="text-sm text-[var(--text-primary)]">{getStepLabel(step.name)}</span>
|
||||
{#if step.message}
|
||||
<span class="text-xs text-[var(--text-tertiary)]">— {step.message}</span>
|
||||
{/if}
|
||||
{:else}
|
||||
<span class="flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full bg-red-100 dark:bg-red-950">
|
||||
<IconX size={14} class="text-red-600 dark:text-red-400" />
|
||||
</span>
|
||||
<span class="text-sm text-[var(--text-primary)]">{getStepLabel(step.name)}</span>
|
||||
{#if step.message}
|
||||
<span class="text-xs text-[var(--text-tertiary)]">— {step.message}</span>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{#if !step.passed && step.hint}
|
||||
<p class="ml-7 mt-1 text-xs text-amber-600 dark:text-amber-400">{step.hint}</p>
|
||||
{/if}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
Reference in New Issue
Block a user