CI / changes (push) Successful in 6s
CI / openapi (push) Has been skipped
CI / go (push) Successful in 43s
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, , evobgp-web) (push) Successful in 1m8s
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, evobgp-all, evobgp-web-all) (push) Successful in 1m9s
CI / docker-bird (push) Has been skipped
CI / bird2 (push) Successful in 17s
CI / docker-go-prime (push) Successful in 23s
CI / docker-go (deploy/docker/evobgp-agent/Dockerfile, , evobgp-agent) (push) Successful in 1m5s
CI / docker-go (evobgp-all, 1, deploy/docker/gobinary/Dockerfile, , evobgp-all) (push) Successful in 2m29s
CI / docker-go (evobgp-api, 1, deploy/docker/gobinary/Dockerfile, , evobgp-api) (push) Successful in 1m31s
CI / docker-go (evobgp-deploy, 0, deploy/docker/gobinary/Dockerfile, , evobgp-deploy) (push) Successful in 1m27s
CI / docker-go (evobgp-ingest, 0, deploy/docker/gobinary/Dockerfile, , evobgp-ingest) (push) Successful in 1m27s
CI / docker-go (evobgp-node, 0, deploy/docker/gobinary/Dockerfile, , evobgp-node) (push) Successful in 1m15s
CI / docker-go (evobgp-render, 0, deploy/docker/gobinary/Dockerfile, , evobgp-render) (push) Successful in 1m28s
CI / docker-go (evobgp-scheduler, 0, deploy/docker/gobinary/Dockerfile, , evobgp-scheduler) (push) Successful in 1m30s
158 lines
5.4 KiB
Svelte
158 lines
5.4 KiB
Svelte
<script lang="ts">
|
|
import type { BirdStatus } from '$lib/api/types.js';
|
|
import { Badge } from '$lib/components/ui/badge/index.js';
|
|
import { Button } from '$lib/components/ui/button/index.js';
|
|
import { Card } from '$lib/components/ui/card/index.js';
|
|
import RefreshCw from '@lucide/svelte/icons/refresh-cw';
|
|
import Play from '@lucide/svelte/icons/play';
|
|
import RotateCcw from '@lucide/svelte/icons/rotate-ccw';
|
|
import Bird from '@lucide/svelte/icons/bird';
|
|
import { cn } from '$lib/utils.js';
|
|
|
|
type Props = {
|
|
applying: boolean;
|
|
reloading: boolean;
|
|
birdLoading: boolean;
|
|
birdStatus: BirdStatus | null;
|
|
onApply: () => void;
|
|
onReload: () => void;
|
|
onRefreshBirdStatus: () => void;
|
|
onOpenBirdProtocols: () => void;
|
|
birdHealthyBadgeVariant: (h: boolean | null | undefined) => 'default' | 'secondary' | 'outline' | 'destructive';
|
|
birdHealthyShortLabel: (h: boolean | null | undefined) => string;
|
|
};
|
|
|
|
let {
|
|
applying,
|
|
reloading,
|
|
birdLoading,
|
|
birdStatus,
|
|
onApply,
|
|
onReload,
|
|
onRefreshBirdStatus,
|
|
onOpenBirdProtocols,
|
|
birdHealthyBadgeVariant,
|
|
birdHealthyShortLabel
|
|
}: Props = $props();
|
|
</script>
|
|
|
|
<div class="grid grid-cols-1 items-stretch gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
|
<Card
|
|
class={cn(
|
|
'min-w-0 overflow-hidden border-l-4 border-l-chart-1 bg-chart-1/5 p-4 shadow-sm'
|
|
)}
|
|
>
|
|
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
|
<div class="flex min-w-0 flex-1 gap-3">
|
|
<div
|
|
class="bg-chart-1/20 flex size-11 shrink-0 items-center justify-center rounded-xl"
|
|
aria-hidden="true"
|
|
>
|
|
<Play class="text-chart-1 size-5" />
|
|
</div>
|
|
<div class="min-w-0 flex-1 space-y-1">
|
|
<p class="font-semibold">Применить ко всем спикерам</p>
|
|
<p class="text-muted-foreground max-w-[42ch] text-sm">Применить текущую конфигурацию на всех BIRD-спикерах</p>
|
|
</div>
|
|
</div>
|
|
<Button class="w-full shrink-0 self-start sm:w-auto sm:self-auto" onclick={onApply} disabled={applying}>
|
|
<Play class="size-4" aria-hidden="true" />
|
|
Применить
|
|
</Button>
|
|
</div>
|
|
</Card>
|
|
|
|
<Card
|
|
class={cn(
|
|
'min-w-0 overflow-hidden border-l-4 border-l-chart-4 bg-chart-4/5 p-4 shadow-sm'
|
|
)}
|
|
>
|
|
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
|
<div class="flex min-w-0 flex-1 gap-3">
|
|
<div
|
|
class="bg-chart-4/20 flex size-11 shrink-0 items-center justify-center rounded-xl"
|
|
aria-hidden="true"
|
|
>
|
|
<RotateCcw class="text-chart-4 size-5" />
|
|
</div>
|
|
<div class="min-w-0 flex-1 space-y-1">
|
|
<p class="font-semibold">Перезагрузка BIRD</p>
|
|
<p class="text-muted-foreground max-w-[42ch] text-sm">Перезагрузить конфигурацию BIRD на всех спикерах</p>
|
|
</div>
|
|
</div>
|
|
<Button
|
|
variant="outline"
|
|
class="w-full shrink-0 self-start sm:w-auto sm:self-auto"
|
|
onclick={onReload}
|
|
disabled={reloading}
|
|
>
|
|
<RotateCcw class="size-4" aria-hidden="true" />
|
|
Перезагрузить
|
|
</Button>
|
|
</div>
|
|
</Card>
|
|
|
|
<Card
|
|
class={cn(
|
|
'min-w-0 overflow-hidden border-l-4 border-l-info bg-info/10 p-4 shadow-sm sm:col-span-2 xl:col-span-1'
|
|
)}
|
|
>
|
|
<div class="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
|
<div class="min-w-0 flex-1 space-y-1">
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
<div
|
|
class="bg-info/15 mr-0.5 flex size-9 items-center justify-center rounded-lg"
|
|
aria-hidden="true"
|
|
>
|
|
<Bird class="text-info size-5 shrink-0" />
|
|
</div>
|
|
<p class="font-semibold">Состояние BIRD</p>
|
|
{#if birdStatus}
|
|
<Badge variant={birdHealthyBadgeVariant(birdStatus.healthy)}>{birdHealthyShortLabel(birdStatus.healthy)}</Badge>
|
|
{/if}
|
|
</div>
|
|
<p class="text-foreground/80 max-w-[56ch] text-sm">
|
|
Локально на хосте API: <code class="bg-muted rounded px-1 text-xs">birdc show protocols</code>. Не заменяет мониторинг спикеров.
|
|
</p>
|
|
{#if birdLoading}
|
|
<p class="text-foreground/80 text-sm">Загрузка…</p>
|
|
{:else if birdStatus}
|
|
{#if !birdStatus.birdc_configured}
|
|
<p class="text-foreground/80 text-sm">{birdStatus.message ?? 'birdc не настроен на API.'}</p>
|
|
{:else if birdStatus.error}
|
|
<p class="text-destructive text-sm">{birdStatus.error}</p>
|
|
{:else}
|
|
<p class="text-sm">
|
|
<span class="text-muted-foreground">BGP сессий:</span>
|
|
<span class="font-medium">{birdStatus.bgp_established}</span>
|
|
<span class="text-muted-foreground">/</span>
|
|
<span class="font-medium">{birdStatus.bgp_sessions_total}</span>
|
|
<span class="text-muted-foreground"> установлено / всего</span>
|
|
</p>
|
|
{/if}
|
|
{:else}
|
|
<p class="text-foreground/80 text-sm">Статус не загружен</p>
|
|
{/if}
|
|
</div>
|
|
|
|
<div class="flex w-full shrink-0 flex-wrap gap-2 sm:w-auto sm:flex-col sm:items-stretch">
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
class="w-full sm:w-auto"
|
|
onclick={onRefreshBirdStatus}
|
|
disabled={birdLoading}
|
|
>
|
|
<RefreshCw class={birdLoading ? 'size-3.5 animate-spin' : 'size-3.5'} />
|
|
Обновить
|
|
</Button>
|
|
{#if birdStatus?.birdc_configured && birdStatus.protocols_excerpt}
|
|
<Button variant="ghost" size="sm" class="w-full sm:w-auto" onclick={onOpenBirdProtocols}>
|
|
Вывод birdc
|
|
</Button>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
</div>
|