refactor: improve code consistency and formatting across components
CI / changes (push) Successful in 7s
CI / openapi (push) Has been skipped
CI / web (push) Successful in 29s
CI / go (push) Has been skipped
CI / docker-web (push) Successful in 1m22s
CI / docker-bird (push) Has been skipped
CI / bird2 (push) Has been skipped
CI / docker-go (push) Has been skipped
CI / changes (push) Successful in 7s
CI / openapi (push) Has been skipped
CI / web (push) Successful in 29s
CI / go (push) Has been skipped
CI / docker-web (push) Successful in 1m22s
CI / docker-bird (push) Has been skipped
CI / bird2 (push) Has been skipped
CI / docker-go (push) Has been skipped
- Standardized formatting in various Svelte components for better readability. - Updated README.md and .prettierrc for consistent styling and improved documentation. - Refactored class attributes in UI components to enhance clarity and maintainability. - Adjusted layout files to ensure proper alignment and spacing in the application interface.
This commit is contained in:
@@ -1,7 +1,13 @@
|
||||
<script lang="ts">
|
||||
import type { RevisionDiff, RevisionPrefix, RevisionRow } from '$lib/api/types.js';
|
||||
import { Button } from '$lib/components/ui/button/index.js';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '$lib/components/ui/card/index.js';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle
|
||||
} from '$lib/components/ui/card/index.js';
|
||||
import { sortRevisionDiffItems } from '$lib/sort-prefixes.js';
|
||||
|
||||
type Props = {
|
||||
@@ -79,7 +85,7 @@
|
||||
<select
|
||||
value={diffRevA}
|
||||
onchange={(e) => onDiffRevAChange((e.currentTarget as HTMLSelectElement).value)}
|
||||
class="border-border bg-background h-8 min-w-0 flex-1 rounded-md border px-2 text-sm"
|
||||
class="h-8 min-w-0 flex-1 rounded-md border border-border bg-background px-2 text-sm"
|
||||
>
|
||||
<option value="">Ревизия A</option>
|
||||
{#each revisions as rev (rev.id)}
|
||||
@@ -89,51 +95,58 @@
|
||||
<select
|
||||
value={diffRevB}
|
||||
onchange={(e) => onDiffRevBChange((e.currentTarget as HTMLSelectElement).value)}
|
||||
class="border-border bg-background h-8 min-w-0 flex-1 rounded-md border px-2 text-sm"
|
||||
class="h-8 min-w-0 flex-1 rounded-md border border-border bg-background px-2 text-sm"
|
||||
>
|
||||
<option value="">Ревизия B</option>
|
||||
{#each revisions as rev (rev.id)}
|
||||
<option value={rev.id}>{rev.id.slice(0, 8)}… ({formatDate(rev.created_at)})</option>
|
||||
{/each}
|
||||
</select>
|
||||
<Button size="sm" class="shrink-0 self-start sm:self-auto" onclick={onLoadDiff} disabled={diffLoading}>
|
||||
<Button
|
||||
size="sm"
|
||||
class="shrink-0 self-start sm:self-auto"
|
||||
onclick={onLoadDiff}
|
||||
disabled={diffLoading}
|
||||
>
|
||||
{diffLoading ? 'Загрузка…' : 'Сравнить'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{#if diffData}
|
||||
<div
|
||||
class="border-border grid min-h-0 grid-cols-1 overflow-hidden rounded-md border sm:grid-cols-2"
|
||||
class="grid min-h-0 grid-cols-1 overflow-hidden rounded-md border border-border sm:grid-cols-2"
|
||||
style="scrollbar-gutter: stable;"
|
||||
>
|
||||
<!-- + Добавлено -->
|
||||
<div class="border-border flex min-h-0 min-w-0 flex-col border-b sm:border-r sm:border-b-0">
|
||||
<div class="flex min-h-0 min-w-0 flex-col border-b border-border sm:border-r sm:border-b-0">
|
||||
<div
|
||||
class="border-border bg-muted/60 flex shrink-0 items-center border-b px-3 py-2 font-mono text-xs font-semibold text-green-600 dark:text-green-400"
|
||||
class="flex shrink-0 items-center border-b border-border bg-muted/60 px-3 py-2 font-mono text-xs font-semibold text-green-600 dark:text-green-400"
|
||||
>
|
||||
<span class="text-muted-foreground mr-2 w-10 shrink-0 select-none text-right">+</span>
|
||||
<span class="mr-2 w-10 shrink-0 text-right text-muted-foreground select-none">+</span>
|
||||
<span>Добавлено ({addedSorted.length})</span>
|
||||
</div>
|
||||
<div
|
||||
bind:this={scrollAddedEl}
|
||||
class="bg-background/50 max-h-[min(28rem,70vh)] min-h-0 overflow-x-auto overflow-y-scroll overscroll-contain"
|
||||
class="max-h-[min(28rem,70vh)] min-h-0 overflow-x-auto overflow-y-scroll overscroll-contain bg-background/50"
|
||||
onscroll={syncFromAdded}
|
||||
>
|
||||
{#if addedSorted.length === 0}
|
||||
<p class="text-muted-foreground p-3 font-mono text-xs">Нет изменений</p>
|
||||
<p class="p-3 font-mono text-xs text-muted-foreground">Нет изменений</p>
|
||||
{:else}
|
||||
<table class="w-full border-collapse font-mono text-xs">
|
||||
<tbody>
|
||||
{#each addedSorted as line, i (`a-${i}-${line}`)}
|
||||
<tr
|
||||
class="border-border/50 hover:bg-muted/30 border-b border-l-2 border-l-green-500/80 bg-green-500/[0.08] dark:bg-green-500/15"
|
||||
class="border-b border-l-2 border-border/50 border-l-green-500/80 bg-green-500/[0.08] hover:bg-muted/30 dark:bg-green-500/15"
|
||||
>
|
||||
<td
|
||||
class="text-muted-foreground w-10 shrink-0 border-r border-transparent py-0.5 pr-1 pl-2 text-right align-top text-[11px] tabular-nums select-none"
|
||||
class="w-10 shrink-0 border-r border-transparent py-0.5 pr-1 pl-2 text-right align-top text-[11px] text-muted-foreground tabular-nums select-none"
|
||||
>
|
||||
{i + 1}
|
||||
</td>
|
||||
<td class="text-foreground max-w-0 break-all py-0.5 pr-3 pl-1 whitespace-pre-wrap">
|
||||
<td
|
||||
class="max-w-0 py-0.5 pr-3 pl-1 break-all whitespace-pre-wrap text-foreground"
|
||||
>
|
||||
{line}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -147,31 +160,33 @@
|
||||
<!-- − Удалено -->
|
||||
<div class="flex min-h-0 min-w-0 flex-col">
|
||||
<div
|
||||
class="border-border bg-muted/60 flex shrink-0 items-center border-b px-3 py-2 font-mono text-xs font-semibold text-red-600 dark:text-red-400"
|
||||
class="flex shrink-0 items-center border-b border-border bg-muted/60 px-3 py-2 font-mono text-xs font-semibold text-red-600 dark:text-red-400"
|
||||
>
|
||||
<span class="text-muted-foreground mr-2 w-10 shrink-0 select-none text-right">−</span>
|
||||
<span class="mr-2 w-10 shrink-0 text-right text-muted-foreground select-none">−</span>
|
||||
<span>Удалено ({removedSorted.length})</span>
|
||||
</div>
|
||||
<div
|
||||
bind:this={scrollRemovedEl}
|
||||
class="bg-background/50 max-h-[min(28rem,70vh)] min-h-0 overflow-x-auto overflow-y-scroll overscroll-contain"
|
||||
class="max-h-[min(28rem,70vh)] min-h-0 overflow-x-auto overflow-y-scroll overscroll-contain bg-background/50"
|
||||
onscroll={syncFromRemoved}
|
||||
>
|
||||
{#if removedSorted.length === 0}
|
||||
<p class="text-muted-foreground p-3 font-mono text-xs">Нет изменений</p>
|
||||
<p class="p-3 font-mono text-xs text-muted-foreground">Нет изменений</p>
|
||||
{:else}
|
||||
<table class="w-full border-collapse font-mono text-xs">
|
||||
<tbody>
|
||||
{#each removedSorted as line, i (`r-${i}-${line}`)}
|
||||
<tr
|
||||
class="border-border/50 hover:bg-muted/30 border-b border-l-2 border-l-red-500/80 bg-red-500/[0.08] dark:bg-red-500/15"
|
||||
class="border-b border-l-2 border-border/50 border-l-red-500/80 bg-red-500/[0.08] hover:bg-muted/30 dark:bg-red-500/15"
|
||||
>
|
||||
<td
|
||||
class="text-muted-foreground w-10 shrink-0 border-r border-transparent py-0.5 pr-1 pl-2 text-right align-top text-[11px] tabular-nums select-none"
|
||||
class="w-10 shrink-0 border-r border-transparent py-0.5 pr-1 pl-2 text-right align-top text-[11px] text-muted-foreground tabular-nums select-none"
|
||||
>
|
||||
{i + 1}
|
||||
</td>
|
||||
<td class="text-foreground max-w-0 break-all py-0.5 pr-3 pl-1 whitespace-pre-wrap">
|
||||
<td
|
||||
class="max-w-0 py-0.5 pr-3 pl-1 break-all whitespace-pre-wrap text-foreground"
|
||||
>
|
||||
{line}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
|
||||
<div class="space-y-3 rounded-lg border border-border/80 bg-muted/15 p-3">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<Filter class="text-muted-foreground size-4 shrink-0" aria-hidden="true" />
|
||||
<Filter class="size-4 shrink-0 text-muted-foreground" aria-hidden="true" />
|
||||
<span class="text-sm font-medium">Фильтры задач</span>
|
||||
<div class="ml-auto flex flex-wrap gap-1.5">
|
||||
<Button
|
||||
@@ -84,7 +84,14 @@
|
||||
>
|
||||
В работе
|
||||
</Button>
|
||||
<Button type="button" variant="ghost" size="sm" class="h-7 text-xs" {disabled} onclick={onResetFilters}>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="h-7 text-xs"
|
||||
{disabled}
|
||||
onclick={onResetFilters}
|
||||
>
|
||||
<X class="size-3.5" aria-hidden="true" />
|
||||
Сброс
|
||||
</Button>
|
||||
@@ -93,7 +100,7 @@
|
||||
|
||||
<div class="relative">
|
||||
<Search
|
||||
class="text-muted-foreground pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2"
|
||||
class="pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<Input
|
||||
@@ -113,7 +120,7 @@
|
||||
<Label for="job-filter-status" class="text-xs">Статус</Label>
|
||||
<select
|
||||
id="job-filter-status"
|
||||
class="border-border bg-background h-9 w-full rounded-md border px-2 text-sm"
|
||||
class="h-9 w-full rounded-md border border-border bg-background px-2 text-sm"
|
||||
value={filterStatus}
|
||||
onchange={(e) => onFilterStatusChange((e.currentTarget as HTMLSelectElement).value)}
|
||||
{disabled}
|
||||
@@ -127,7 +134,7 @@
|
||||
<Label for="job-filter-kind" class="text-xs">Тип задачи</Label>
|
||||
<select
|
||||
id="job-filter-kind"
|
||||
class="border-border bg-background h-9 w-full rounded-md border px-2 text-sm"
|
||||
class="h-9 w-full rounded-md border border-border bg-background px-2 text-sm"
|
||||
value={filterKind}
|
||||
onchange={(e) => onFilterKindChange((e.currentTarget as HTMLSelectElement).value)}
|
||||
{disabled}
|
||||
@@ -141,7 +148,7 @@
|
||||
<Label for="job-filter-module" class="text-xs">Модуль (локально)</Label>
|
||||
<select
|
||||
id="job-filter-module"
|
||||
class="border-border bg-background h-9 w-full rounded-md border px-2 text-sm"
|
||||
class="h-9 w-full rounded-md border border-border bg-background px-2 text-sm"
|
||||
value={filterModuleId}
|
||||
onchange={(e) => onFilterModuleIdChange((e.currentTarget as HTMLSelectElement).value)}
|
||||
{disabled}
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
<CardDescription class="flex flex-wrap items-center gap-x-2 gap-y-1">
|
||||
<span>Фоновые задачи (ingest, применение, обновление)</span>
|
||||
{#if jobsFetchedTotal !== undefined}
|
||||
<span class="text-muted-foreground font-normal tabular-nums">
|
||||
<span class="font-normal text-muted-foreground tabular-nums">
|
||||
· Показано {jobs.length} из {jobsFetchedTotal}
|
||||
</span>
|
||||
{/if}
|
||||
@@ -163,20 +163,18 @@
|
||||
<div
|
||||
class="rounded-md border border-chart-1/25 bg-chart-1/5 px-2.5 py-2 dark:bg-chart-1/10"
|
||||
>
|
||||
<p
|
||||
class="text-chart-1 flex items-center gap-1 text-[11px] font-medium uppercase"
|
||||
>
|
||||
<p class="flex items-center gap-1 text-[11px] font-medium text-chart-1 uppercase">
|
||||
<CircleDot class="size-3.5 shrink-0" aria-hidden="true" />
|
||||
Статус
|
||||
</p>
|
||||
<Badge class="mt-1" variant={jobStatusVariant(job.status)}>{jobStatusRu(job.status)}</Badge>
|
||||
<Badge class="mt-1" variant={jobStatusVariant(job.status)}
|
||||
>{jobStatusRu(job.status)}</Badge
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="rounded-md border border-chart-2/25 bg-chart-2/5 px-2.5 py-2 dark:bg-chart-2/10"
|
||||
>
|
||||
<p
|
||||
class="text-chart-2 flex items-center gap-1 text-[11px] font-medium uppercase"
|
||||
>
|
||||
<p class="flex items-center gap-1 text-[11px] font-medium text-chart-2 uppercase">
|
||||
<CalendarClock class="size-3.5 shrink-0" aria-hidden="true" />
|
||||
Создана
|
||||
</p>
|
||||
@@ -185,9 +183,7 @@
|
||||
<div
|
||||
class="rounded-md border border-chart-3/25 bg-chart-3/5 px-2.5 py-2 dark:bg-chart-3/10"
|
||||
>
|
||||
<p
|
||||
class="text-chart-3 flex items-center gap-1 text-[11px] font-medium uppercase"
|
||||
>
|
||||
<p class="flex items-center gap-1 text-[11px] font-medium text-chart-3 uppercase">
|
||||
<PlayCircle class="size-3.5 shrink-0" aria-hidden="true" />
|
||||
Запущена
|
||||
</p>
|
||||
@@ -196,9 +192,7 @@
|
||||
<div
|
||||
class="rounded-md border border-chart-4/25 bg-chart-4/5 px-2.5 py-2 dark:bg-chart-4/10"
|
||||
>
|
||||
<p
|
||||
class="text-chart-4 flex items-center gap-1 text-[11px] font-medium uppercase"
|
||||
>
|
||||
<p class="flex items-center gap-1 text-[11px] font-medium text-chart-4 uppercase">
|
||||
<Flag class="size-3.5 shrink-0" aria-hidden="true" />
|
||||
Завершена
|
||||
</p>
|
||||
@@ -343,7 +337,7 @@
|
||||
class="min-w-0 overflow-hidden rounded-md border border-chart-1/30 bg-chart-1/5 p-2.5 dark:bg-chart-1/10"
|
||||
>
|
||||
<p
|
||||
class="text-chart-1 flex items-center gap-1 text-[11px] font-medium uppercase"
|
||||
class="flex items-center gap-1 text-[11px] font-medium text-chart-1 uppercase"
|
||||
>
|
||||
<Layers class="size-3.5 shrink-0" aria-hidden="true" />
|
||||
Агрегация
|
||||
@@ -354,7 +348,7 @@
|
||||
class="min-w-0 overflow-hidden rounded-md border border-chart-2/30 bg-chart-2/5 p-2.5 dark:bg-chart-2/10"
|
||||
>
|
||||
<p
|
||||
class="text-chart-2 flex items-center gap-1 text-[11px] font-medium uppercase"
|
||||
class="flex items-center gap-1 text-[11px] font-medium text-chart-2 uppercase"
|
||||
>
|
||||
<Globe class="size-3.5 shrink-0" aria-hidden="true" />
|
||||
Домены
|
||||
@@ -365,7 +359,7 @@
|
||||
class="min-w-0 overflow-hidden rounded-md border border-chart-3/30 bg-chart-3/5 p-2.5 dark:bg-chart-3/10"
|
||||
>
|
||||
<p
|
||||
class="text-chart-3 flex items-center gap-1 text-[11px] font-medium uppercase"
|
||||
class="flex items-center gap-1 text-[11px] font-medium text-chart-3 uppercase"
|
||||
>
|
||||
<Binary class="size-3.5 shrink-0" aria-hidden="true" />
|
||||
ASN
|
||||
@@ -376,7 +370,7 @@
|
||||
class="min-w-0 overflow-hidden rounded-md border border-chart-4/30 bg-chart-4/5 p-2.5 dark:bg-chart-4/10"
|
||||
>
|
||||
<p
|
||||
class="text-chart-4 flex items-center gap-1 text-[11px] font-medium uppercase"
|
||||
class="flex items-center gap-1 text-[11px] font-medium text-chart-4 uppercase"
|
||||
>
|
||||
<Link2 class="size-3.5 shrink-0" aria-hidden="true" />
|
||||
CDN / IP-диапазоны
|
||||
@@ -427,7 +421,9 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="min-w-0 space-y-1.5 rounded-lg border p-3">
|
||||
<p class="text-sm font-medium">IP-диапазоны: итог по статическим диапазонам</p>
|
||||
<p class="text-sm font-medium">
|
||||
IP-диапазоны: итог по статическим диапазонам
|
||||
</p>
|
||||
<JobReportTableBlock
|
||||
rows={jobReport.ipRanges as RowData[]}
|
||||
columns={reportCols}
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
onReload: () => void;
|
||||
onRefreshBirdStatus: () => void;
|
||||
onOpenBirdProtocols: () => void;
|
||||
birdHealthyBadgeVariant: (h: boolean | null | undefined) => 'default' | 'secondary' | 'outline' | 'destructive';
|
||||
birdHealthyBadgeVariant: (
|
||||
h: boolean | null | undefined
|
||||
) => 'default' | 'secondary' | 'outline' | 'destructive';
|
||||
birdHealthyShortLabel: (h: boolean | null | undefined) => string;
|
||||
};
|
||||
|
||||
@@ -38,24 +40,28 @@
|
||||
|
||||
<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'
|
||||
)}
|
||||
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"
|
||||
class="flex size-11 shrink-0 items-center justify-center rounded-xl bg-chart-1/20"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<Play class="text-chart-1 size-5" />
|
||||
<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="text-muted-foreground max-w-[42ch] text-sm">Применить текущую конфигурацию на всех BIRD-спикерах</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}>
|
||||
<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>
|
||||
@@ -63,21 +69,21 @@
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
class={cn(
|
||||
'min-w-0 overflow-hidden border-l-4 border-l-chart-4 bg-chart-4/5 p-4 shadow-sm'
|
||||
)}
|
||||
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"
|
||||
class="flex size-11 shrink-0 items-center justify-center rounded-xl bg-chart-4/20"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<RotateCcw class="text-chart-4 size-5" />
|
||||
<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="text-muted-foreground max-w-[42ch] text-sm">Перезагрузить конфигурацию BIRD на всех спикерах</p>
|
||||
<p class="max-w-[42ch] text-sm text-muted-foreground">
|
||||
Перезагрузить конфигурацию BIRD на всех спикерах
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
@@ -101,26 +107,32 @@
|
||||
<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"
|
||||
class="mr-0.5 flex size-9 items-center justify-center rounded-lg bg-info/15"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<Bird class="text-info size-5 shrink-0" />
|
||||
<Bird class="size-5 shrink-0 text-info" />
|
||||
</div>
|
||||
<p class="font-semibold">Состояние BIRD</p>
|
||||
{#if birdStatus}
|
||||
<Badge variant={birdHealthyBadgeVariant(birdStatus.healthy)}>{birdHealthyShortLabel(birdStatus.healthy)}</Badge>
|
||||
<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 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-foreground/80 text-sm">Загрузка…</p>
|
||||
<p class="text-sm text-foreground/80">Загрузка…</p>
|
||||
{:else if birdStatus}
|
||||
{#if !birdStatus.birdc_configured}
|
||||
<p class="text-foreground/80 text-sm">{birdStatus.message ?? 'birdc не настроен на API.'}</p>
|
||||
<p class="text-sm text-foreground/80">
|
||||
{birdStatus.message ?? 'birdc не настроен на API.'}
|
||||
</p>
|
||||
{:else if birdStatus.error}
|
||||
<p class="text-destructive text-sm">{birdStatus.error}</p>
|
||||
<p class="text-sm text-destructive">{birdStatus.error}</p>
|
||||
{:else}
|
||||
<p class="text-sm">
|
||||
<span class="text-muted-foreground">BGP сессий:</span>
|
||||
@@ -131,7 +143,7 @@
|
||||
</p>
|
||||
{/if}
|
||||
{:else}
|
||||
<p class="text-foreground/80 text-sm">Статус не загружен</p>
|
||||
<p class="text-sm text-foreground/80">Статус не загружен</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
<script lang="ts">
|
||||
import type { RevisionRow } from '$lib/api/types.js';
|
||||
import { Button } from '$lib/components/ui/button/index.js';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '$lib/components/ui/card/index.js';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle
|
||||
} from '$lib/components/ui/card/index.js';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -41,60 +47,69 @@
|
||||
<div class="min-w-0 flex-1">
|
||||
<CardTitle class="text-base">История ревизий</CardTitle>
|
||||
<CardDescription class="max-w-[75ch]">
|
||||
Создаются задачей module_refresh (CDN / IP / AS и т.д.); в превью есть полный текст BIRD с инклюдами
|
||||
Создаются задачей module_refresh (CDN / IP / AS и т.д.); в превью есть полный текст BIRD с
|
||||
инклюдами
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" class="shrink-0 self-start sm:self-auto" onclick={onReload} disabled={revLoading}>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="shrink-0 self-start sm:self-auto"
|
||||
onclick={onReload}
|
||||
disabled={revLoading}
|
||||
>
|
||||
<RefreshCw class={revLoading ? 'animate-spin' : ''} />
|
||||
</Button>
|
||||
</CardHeader>
|
||||
<CardContent class="min-w-0 p-0">
|
||||
<div class="max-w-full overflow-x-auto overscroll-x-contain [scrollbar-gutter:stable]">
|
||||
<Table class="min-w-[44rem]">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>ID</TableHead>
|
||||
<TableHead>Создана</TableHead>
|
||||
<TableHead>Префиксов</TableHead>
|
||||
<TableHead>Хэш</TableHead>
|
||||
<TableHead class="w-32"></TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#each revisions as rev (rev.id)}
|
||||
<Table class="min-w-[44rem]">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableCell class="font-mono text-xs">{rev.id.slice(0, 8)}…</TableCell>
|
||||
<TableCell class="text-sm">{formatDate(rev.created_at)}</TableCell>
|
||||
<TableCell>{rev.materialized_prefix_count}</TableCell>
|
||||
<TableCell class="font-mono text-xs text-muted-foreground">{rev.content_hash.slice(0, 12)}…</TableCell>
|
||||
<TableCell>
|
||||
<div class="flex gap-1">
|
||||
<Button variant="ghost" size="icon-sm" onclick={() => onOpenPreview(rev)}>
|
||||
<Eye class="size-3.5" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon-sm" onclick={() => onRollbackRequest(rev)}>
|
||||
<Undo class="size-3.5" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
title="Скачать диагностический лог"
|
||||
onclick={() => onDownloadDiagnosticLog(rev)}
|
||||
>
|
||||
<Download class="size-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableHead>ID</TableHead>
|
||||
<TableHead>Создана</TableHead>
|
||||
<TableHead>Префиксов</TableHead>
|
||||
<TableHead>Хэш</TableHead>
|
||||
<TableHead class="w-32"></TableHead>
|
||||
</TableRow>
|
||||
{:else}
|
||||
<TableRow>
|
||||
<TableCell colspan={5} class="text-muted-foreground py-8 text-center">
|
||||
{revLoading ? 'Загрузка…' : 'Нет ревизий'}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{/each}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#each revisions as rev (rev.id)}
|
||||
<TableRow>
|
||||
<TableCell class="font-mono text-xs">{rev.id.slice(0, 8)}…</TableCell>
|
||||
<TableCell class="text-sm">{formatDate(rev.created_at)}</TableCell>
|
||||
<TableCell>{rev.materialized_prefix_count}</TableCell>
|
||||
<TableCell class="font-mono text-xs text-muted-foreground"
|
||||
>{rev.content_hash.slice(0, 12)}…</TableCell
|
||||
>
|
||||
<TableCell>
|
||||
<div class="flex gap-1">
|
||||
<Button variant="ghost" size="icon-sm" onclick={() => onOpenPreview(rev)}>
|
||||
<Eye class="size-3.5" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon-sm" onclick={() => onRollbackRequest(rev)}>
|
||||
<Undo class="size-3.5" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
title="Скачать диагностический лог"
|
||||
onclick={() => onDownloadDiagnosticLog(rev)}
|
||||
>
|
||||
<Download class="size-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{:else}
|
||||
<TableRow>
|
||||
<TableCell colspan={5} class="text-muted-foreground py-8 text-center">
|
||||
{revLoading ? 'Загрузка…' : 'Нет ревизий'}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{/each}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user