Files
EvoBGP/apps/web/src/lib/components/operations/OperationsQuickActions.svelte
T
Denozordec a37c931ee7
CI / changes (push) Successful in 10s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 27s
CI / web (push) Successful in 38s
CI / go (push) Successful in 2m36s
CI / bird2 (push) Successful in 15s
CI / release (push) Failing after 3m7s
feat(monorepo): restructure web components and update configurations
Refactored the project structure to support a monorepo setup, moving the web application to `apps/web/` and updating related configurations. Adjusted pre-commit hooks to use `pnpm` for linting and formatting. Updated CI workflows to reflect the new directory structure and dependencies. Removed legacy files and configurations from the previous `web/` directory, streamlining the project for better maintainability and clarity.
2026-06-30 23:54:28 +07:00

175 lines
5.7 KiB
Svelte

<script lang="ts">
import type { BirdStatus } from '$lib/api/types.js';
import { Badge } from '@evobgp/ui/components/badge/index.js';
import { Button } from '@evobgp/ui/components/button/index.js';
import { Card } from '@evobgp/ui/components/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="flex size-11 shrink-0 items-center justify-center rounded-xl bg-chart-1/20"
aria-hidden="true"
>
<Play class="size-5 text-chart-1" />
</div>
<div class="min-w-0 flex-1 space-y-1">
<p class="font-semibold">Применить ко всем спикерам</p>
<p class="max-w-[42ch] text-sm text-muted-foreground">
Применить текущую конфигурацию на всех 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="flex size-11 shrink-0 items-center justify-center rounded-xl bg-chart-4/20"
aria-hidden="true"
>
<RotateCcw class="size-5 text-chart-4" />
</div>
<div class="min-w-0 flex-1 space-y-1">
<p class="font-semibold">Перезагрузка BIRD</p>
<p class="max-w-[42ch] text-sm text-muted-foreground">
Перезагрузить конфигурацию 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="mr-0.5 flex size-9 items-center justify-center rounded-lg bg-info/15"
aria-hidden="true"
>
<Bird class="size-5 shrink-0 text-info" />
</div>
<p class="font-semibold">Состояние BIRD</p>
{#if birdStatus}
<Badge
variant={birdHealthyBadgeVariant(birdStatus.healthy)}
class={birdStatus.healthy === true
? 'border-success/30 bg-success/15 text-success'
: undefined}
>
{birdHealthyShortLabel(birdStatus.healthy)}
</Badge>
{/if}
</div>
<p class="max-w-[56ch] text-sm text-foreground/80">
Локально на хосте API: <code class="rounded bg-muted px-1 text-xs"
>birdc show protocols</code
>. Не заменяет мониторинг спикеров.
</p>
{#if birdLoading}
<p class="text-sm text-foreground/80">Загрузка…</p>
{:else if birdStatus}
{#if !birdStatus.birdc_configured}
<p class="text-sm text-foreground/80">
{birdStatus.message ?? 'birdc не настроен на API.'}
</p>
{:else if birdStatus.error}
<p class="text-sm text-destructive">{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-sm text-foreground/80">Статус не загружен</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>