- Added a new function for determining job status badge variants to improve UI consistency. - Refactored imports to utilize the core UI library for better maintainability. - Updated job report and filters components to enhance user experience and streamline functionality. - Improved layout and responsiveness across operations-related components.
175 lines
5.6 KiB
Svelte
175 lines
5.6 KiB
Svelte
<script lang="ts">
|
|
import type { BirdStatus } from '$lib/api/types.js';
|
|
import { Badge } from '$lib/ui/core/badge/index.js';
|
|
import { Button } from '$lib/ui/core/button/index.js';
|
|
import { Card } from '$lib/ui/core/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>
|