Files
tiny-forge/web/src/lib/components/ValidationChecklist.svelte
T
alexei.dolgolyov 79a40f3d9c 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
2026-03-30 11:29:10 +03:00

74 lines
2.4 KiB
Svelte

<!--
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)]">&mdash; {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)]">&mdash; {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}