feat: improve peer speaker assignment UX in network settings
Replace manual speaker id input with a validated speaker selector and clearer speaker labels so operators can configure peers with fewer input mistakes and better context. Made-with: Cursor
This commit is contained in:
@@ -14,6 +14,12 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '$lib/components/ui/card/index.js';
|
||||
import { Input } from '$lib/components/ui/input/index.js';
|
||||
import { Label } from '$lib/components/ui/label/index.js';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger
|
||||
} from '$lib/components/ui/select/index.js';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '$lib/components/ui/tabs/index.js';
|
||||
import {
|
||||
Dialog,
|
||||
@@ -73,6 +79,12 @@
|
||||
let speakerForm = $state<BgpSpeakerCreate>({ endpoint: '', role: 'operator' });
|
||||
let speakerSaving = $state(false);
|
||||
let applyingId = $state<string | null>(null);
|
||||
const speakerById = $derived.by(() => new Map(speakers.map((s) => [s.id, s])));
|
||||
|
||||
function speakerLabelById(id: string | null | undefined) {
|
||||
if (!id) return '—';
|
||||
return speakerById.get(id)?.endpoint ?? id;
|
||||
}
|
||||
|
||||
async function loadAll() {
|
||||
peersLoading = true;
|
||||
@@ -123,8 +135,12 @@
|
||||
}
|
||||
}
|
||||
async function savePeer() {
|
||||
if (!peerForm.neighbor || !peerForm.remote_asn) {
|
||||
toast.error('Укажите адрес и ASN');
|
||||
if (!peerForm.neighbor.trim()) {
|
||||
toast.error('Укажите адрес соседа');
|
||||
return;
|
||||
}
|
||||
if (!peerForm.remote_asn || peerForm.remote_asn <= 0) {
|
||||
toast.error('Remote ASN должен быть больше 0');
|
||||
return;
|
||||
}
|
||||
peerSaving = true;
|
||||
@@ -271,7 +287,7 @@
|
||||
<TableCell>
|
||||
<Badge variant={sessionBadge(p.session_state)}>{p.session_state || '—'}</Badge>
|
||||
</TableCell>
|
||||
<TableCell class="text-muted-foreground font-mono text-xs">{p.bgp_speaker_id ? p.bgp_speaker_id.slice(0, 8) + '…' : '—'}</TableCell>
|
||||
<TableCell class="text-muted-foreground text-xs">{speakerLabelById(p.bgp_speaker_id)}</TableCell>
|
||||
<TableCell>
|
||||
<div class="flex gap-1">
|
||||
<Button variant="ghost" size="icon-sm" onclick={() => openPeerEdit(p)}><Pencil class="size-3.5" /></Button>
|
||||
@@ -325,7 +341,13 @@
|
||||
<TableCell class="font-mono text-xs text-muted-foreground">{s.last_applied_revision_id ? s.last_applied_revision_id.slice(0, 8) + '…' : '—'}</TableCell>
|
||||
<TableCell>
|
||||
<div class="flex gap-1">
|
||||
<Button variant="outline" size="xs" onclick={() => applySpeaker(s.id)} disabled={applyingId === s.id}>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="xs"
|
||||
title="Запустить применение ревизии на спикере"
|
||||
onclick={() => applySpeaker(s.id)}
|
||||
disabled={applyingId === s.id}
|
||||
>
|
||||
<Play class="size-3" />
|
||||
{applyingId === s.id ? 'Apply…' : 'Apply'}
|
||||
</Button>
|
||||
@@ -365,8 +387,26 @@
|
||||
<Input id="p-asn" type="number" placeholder="65000" bind:value={peerForm.remote_asn} />
|
||||
</div>
|
||||
<div class="space-y-1.5">
|
||||
<Label for="p-speaker">Спикер (ID, опционально)</Label>
|
||||
<Input id="p-speaker" placeholder="speaker-id" bind:value={peerForm.bgp_speaker_id} />
|
||||
<Label for="p-speaker">Спикер (опционально)</Label>
|
||||
<Select
|
||||
type="single"
|
||||
value={peerForm.bgp_speaker_id ?? ''}
|
||||
onValueChange={(v) => {
|
||||
peerForm = { ...peerForm, bgp_speaker_id: v || null };
|
||||
}}
|
||||
>
|
||||
<SelectTrigger id="p-speaker" class="w-full">
|
||||
{peerForm.bgp_speaker_id
|
||||
? speakerLabelById(peerForm.bgp_speaker_id)
|
||||
: 'Не выбрано'}
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="">Не выбрано</SelectItem>
|
||||
{#each speakers as s (s.id)}
|
||||
<SelectItem value={s.id}>{s.endpoint} ({s.id.slice(0, 8)}…)</SelectItem>
|
||||
{/each}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div
|
||||
class="border-border bg-muted/30 flex flex-row items-center justify-between gap-4 rounded-lg border p-3"
|
||||
|
||||
Reference in New Issue
Block a user