feat: improve UI layout and responsiveness in module and operations pages. Refactor component structures for better alignment and spacing, ensuring a more consistent user experience across different screen sizes. Enhance button placements and text wrapping for improved readability.
This commit is contained in:
@@ -498,14 +498,14 @@
|
||||
{:else if mod}
|
||||
<div class="space-y-6">
|
||||
<!-- Header -->
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="flex flex-col gap-3 xl:flex-row xl:items-start xl:justify-between">
|
||||
<div class="flex min-w-0 items-start gap-3">
|
||||
<Button variant="ghost" size="icon-sm" href={resolve('/modules')}>
|
||||
<ArrowLeft class="size-4" />
|
||||
</Button>
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<h1 class="text-2xl font-semibold tracking-tight">{mod.name}</h1>
|
||||
<div class="min-w-0">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<h1 class="min-w-0 break-words text-2xl font-semibold tracking-tight">{mod.name}</h1>
|
||||
<Badge variant="outline">{mod.type}</Badge>
|
||||
{#if mod.enabled}
|
||||
<Badge variant="default" class="text-xs">вкл</Badge>
|
||||
@@ -513,10 +513,10 @@
|
||||
<Badge variant="secondary" class="text-xs">выкл</Badge>
|
||||
{/if}
|
||||
</div>
|
||||
<p class="text-muted-foreground mt-0.5 text-sm font-mono text-xs">{mod.id}</p>
|
||||
<p class="text-muted-foreground mt-0.5 break-all font-mono text-xs">{mod.id}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<Button variant="outline" size="sm" onclick={refreshMod} disabled={refreshing}>
|
||||
<RefreshCw class={refreshing ? 'animate-spin' : ''} />
|
||||
Refresh
|
||||
@@ -533,7 +533,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Module metadata -->
|
||||
<div class="grid grid-cols-2 gap-3 sm:grid-cols-4">
|
||||
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 xl:grid-cols-4">
|
||||
<Card class="p-3">
|
||||
<p class="text-muted-foreground text-xs">Приоритет</p>
|
||||
<p class="font-semibold">{mod.priority}</p>
|
||||
@@ -550,21 +550,21 @@
|
||||
</Card>
|
||||
<Card class="p-3">
|
||||
<p class="text-muted-foreground text-xs">Community по умолч.</p>
|
||||
<p class="font-semibold text-sm">{communityLabel(mod.default_community_id)}</p>
|
||||
<p class="font-semibold text-sm break-all">{communityLabel(mod.default_community_id)}</p>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<!-- Entries by type -->
|
||||
{#if mod.type === 'AS_PREFIXES'}
|
||||
<Card>
|
||||
<CardHeader class="flex flex-row items-center justify-between pb-2">
|
||||
<div>
|
||||
<CardHeader class="flex flex-col gap-3 pb-2 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div class="min-w-0 flex-1">
|
||||
<CardTitle class="text-base">AS-записи</CardTitle>
|
||||
<CardDescription>
|
||||
Номер AS и community; имя, число префиксов и дата обновляются при успешном обновлении модуля (RIPEstat)
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Button size="sm" onclick={openAsCreate}><Plus />Добавить</Button>
|
||||
<Button size="sm" class="shrink-0 self-start sm:self-auto" onclick={openAsCreate}><Plus />Добавить</Button>
|
||||
</CardHeader>
|
||||
<CardContent class="p-0">
|
||||
<Table>
|
||||
@@ -615,12 +615,12 @@
|
||||
</Card>
|
||||
{:else if mod.type === 'CDN_CIDRS'}
|
||||
<Card>
|
||||
<CardHeader class="flex flex-row items-center justify-between pb-2">
|
||||
<div>
|
||||
<CardHeader class="flex flex-col gap-3 pb-2 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div class="min-w-0 flex-1">
|
||||
<CardTitle class="text-base">CDN-источники</CardTitle>
|
||||
<CardDescription>URL источников для скачивания списков CIDR</CardDescription>
|
||||
</div>
|
||||
<Button size="sm" onclick={openCdnCreate}><Plus />Добавить</Button>
|
||||
<Button size="sm" class="shrink-0 self-start sm:self-auto" onclick={openCdnCreate}><Plus />Добавить</Button>
|
||||
</CardHeader>
|
||||
<CardContent class="p-0">
|
||||
<Table>
|
||||
@@ -667,12 +667,12 @@
|
||||
</Card>
|
||||
{:else if mod.type === 'DOMAINS'}
|
||||
<Card>
|
||||
<CardHeader class="flex flex-row items-center justify-between pb-2">
|
||||
<div>
|
||||
<CardHeader class="flex flex-col gap-3 pb-2 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div class="min-w-0 flex-1">
|
||||
<CardTitle class="text-base">Домены</CardTitle>
|
||||
<CardDescription>FQDN для резолвинга через DoH</CardDescription>
|
||||
</div>
|
||||
<Button size="sm" onclick={openDomainCreate}><Plus />Добавить</Button>
|
||||
<Button size="sm" class="shrink-0 self-start sm:self-auto" onclick={openDomainCreate}><Plus />Добавить</Button>
|
||||
</CardHeader>
|
||||
<CardContent class="p-0">
|
||||
<Table>
|
||||
@@ -706,12 +706,12 @@
|
||||
</Card>
|
||||
{:else if mod.type === 'IP_RANGES'}
|
||||
<Card>
|
||||
<CardHeader class="flex flex-row items-center justify-between pb-2">
|
||||
<div>
|
||||
<CardHeader class="flex flex-col gap-3 pb-2 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div class="min-w-0 flex-1">
|
||||
<CardTitle class="text-base">IP-диапазоны</CardTitle>
|
||||
<CardDescription>Статические CIDR для анонса</CardDescription>
|
||||
</div>
|
||||
<Button size="sm" onclick={openIpCreate}><Plus />Добавить</Button>
|
||||
<Button size="sm" class="shrink-0 self-start sm:self-auto" onclick={openIpCreate}><Plus />Добавить</Button>
|
||||
</CardHeader>
|
||||
<CardContent class="p-0">
|
||||
<Table>
|
||||
|
||||
@@ -446,24 +446,29 @@
|
||||
<!-- Quick actions + локальный статус BIRD (хост API, если задан EVOBGP_BIRDC_SOCKET) -->
|
||||
<div class="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
||||
<Card class="p-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="font-semibold">Apply all speakers</p>
|
||||
<p class="text-muted-foreground text-sm">Применить текущую конфигурацию на всех спикерах</p>
|
||||
</div>
|
||||
<Button onclick={() => (applyConfirm = true)} disabled={applying}>
|
||||
<Button class="shrink-0 self-start sm:self-auto" onclick={() => (applyConfirm = true)} disabled={applying}>
|
||||
<Play />
|
||||
Apply
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
<Card class="p-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="font-semibold">BIRD Reload</p>
|
||||
<p class="text-muted-foreground text-sm">Перезагрузить конфигурацию BIRD на всех спикерах</p>
|
||||
</div>
|
||||
<Button variant="outline" onclick={() => (reloadConfirm = true)} disabled={reloading}>
|
||||
<Button
|
||||
variant="outline"
|
||||
class="shrink-0 self-start sm:self-auto"
|
||||
onclick={() => (reloadConfirm = true)}
|
||||
disabled={reloading}
|
||||
>
|
||||
<RotateCcw />
|
||||
Reload
|
||||
</Button>
|
||||
@@ -526,12 +531,12 @@
|
||||
<!-- Revisions -->
|
||||
<TabsContent value="revisions" class="mt-4">
|
||||
<Card>
|
||||
<CardHeader class="flex flex-row items-center justify-between pb-2">
|
||||
<div>
|
||||
<CardHeader class="flex flex-col gap-3 pb-2 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div class="min-w-0 flex-1">
|
||||
<CardTitle class="text-base">История ревизий</CardTitle>
|
||||
<CardDescription>Создаются задачей module_refresh (CDN / IP / AS и т.д.); в превью есть полный текст BIRD с инклюдами</CardDescription>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" onclick={loadRevisions} disabled={revLoading}>
|
||||
<Button variant="outline" size="sm" class="shrink-0 self-start sm:self-auto" onclick={loadRevisions} disabled={revLoading}>
|
||||
<RefreshCw class={revLoading ? 'animate-spin' : ''} />
|
||||
</Button>
|
||||
</CardHeader>
|
||||
@@ -585,20 +590,20 @@
|
||||
<CardDescription>Выберите ID двух ревизий для сравнения</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div class="flex gap-2">
|
||||
<select bind:value={diffRevA} class="border-border bg-background h-8 flex-1 rounded-md border px-2 text-sm">
|
||||
<div class="flex flex-col gap-2 sm:flex-row">
|
||||
<select bind:value={diffRevA} class="border-border bg-background h-8 min-w-0 flex-1 rounded-md border px-2 text-sm">
|
||||
<option value="">Ревизия A</option>
|
||||
{#each revisions as rev}
|
||||
<option value={rev.id}>{rev.id.slice(0, 8)}… ({formatDate(rev.created_at)})</option>
|
||||
{/each}
|
||||
</select>
|
||||
<select bind:value={diffRevB} class="border-border bg-background h-8 flex-1 rounded-md border px-2 text-sm">
|
||||
<select bind:value={diffRevB} class="border-border bg-background h-8 min-w-0 flex-1 rounded-md border px-2 text-sm">
|
||||
<option value="">Ревизия B</option>
|
||||
{#each revisions as rev}
|
||||
<option value={rev.id}>{rev.id.slice(0, 8)}… ({formatDate(rev.created_at)})</option>
|
||||
{/each}
|
||||
</select>
|
||||
<Button size="sm" onclick={loadDiff} disabled={diffLoading}>
|
||||
<Button size="sm" class="shrink-0 self-start sm:self-auto" onclick={loadDiff} disabled={diffLoading}>
|
||||
{diffLoading ? 'Загрузка…' : 'Сравнить'}
|
||||
</Button>
|
||||
</div>
|
||||
@@ -633,12 +638,12 @@
|
||||
<!-- Jobs -->
|
||||
<TabsContent value="jobs" class="mt-4">
|
||||
<Card>
|
||||
<CardHeader class="flex flex-row items-center justify-between pb-2">
|
||||
<div>
|
||||
<CardHeader class="flex flex-col gap-3 pb-2 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div class="min-w-0 flex-1">
|
||||
<CardTitle class="text-base">Задачи</CardTitle>
|
||||
<CardDescription>Фоновые задачи (ingest, apply, refresh)</CardDescription>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" onclick={loadJobs} disabled={jobsLoading}>
|
||||
<Button variant="outline" size="sm" class="shrink-0 self-start sm:self-auto" onclick={loadJobs} disabled={jobsLoading}>
|
||||
<RefreshCw class={jobsLoading ? 'animate-spin' : ''} />
|
||||
</Button>
|
||||
</CardHeader>
|
||||
|
||||
Reference in New Issue
Block a user