feat: add enabled state to BGP peer types and UI. Implement peer enabling toggle in the network page, allowing users to enable or disable peers during creation and editing. Update relevant API calls and UI components to reflect the new functionality.
CI / changes (push) Successful in 6s
CI / openapi (push) Has been skipped
CI / go (push) Has been skipped
CI / bird2 (push) Has been skipped
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, , evobgp-web) (push) Successful in 1m0s
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, evobgp-all, evobgp-web-all) (push) Successful in 1m1s
CI / docker-bird (push) Has been skipped
CI / docker-go (deploy/docker/evobgp-agent/Dockerfile, , evobgp-agent) (push) Has been skipped
CI / docker-go (evobgp-all, 1, deploy/docker/gobinary/Dockerfile, , evobgp-all) (push) Has been skipped
CI / docker-go (evobgp-api, 1, deploy/docker/gobinary/Dockerfile, , evobgp-api) (push) Has been skipped
CI / docker-go (evobgp-deploy, 0, deploy/docker/gobinary/Dockerfile, , evobgp-deploy) (push) Has been skipped
CI / docker-go (evobgp-ingest, 0, deploy/docker/gobinary/Dockerfile, , evobgp-ingest) (push) Has been skipped
CI / docker-go (evobgp-node, 0, deploy/docker/gobinary/Dockerfile, , evobgp-node) (push) Has been skipped
CI / docker-go (evobgp-render, 0, deploy/docker/gobinary/Dockerfile, , evobgp-render) (push) Has been skipped
CI / docker-go (evobgp-scheduler, 0, deploy/docker/gobinary/Dockerfile, , evobgp-scheduler) (push) Has been skipped

This commit is contained in:
Denozordec
2026-04-06 01:35:13 +07:00
parent 3e8543177e
commit 80965adc0c
2 changed files with 57 additions and 6 deletions
+2
View File
@@ -123,6 +123,7 @@ export type PeerRow = {
name?: string;
neighbor: string;
remote_asn?: number;
enabled?: boolean;
session_state: string;
bgp_speaker_id: string | null;
};
@@ -131,6 +132,7 @@ export type BgpPeerCreate = {
neighbor: string;
remote_asn: number;
bgp_speaker_id?: string | null;
enabled?: boolean;
};
export type BgpPeerPatch = Partial<BgpPeerCreate>;
+55 -6
View File
@@ -41,6 +41,7 @@
TableHeader,
TableRow
} from '$lib/components/ui/table/index.js';
import { Switch } from '$lib/components/ui/switch/index.js';
import { toast } from 'svelte-sonner';
import Plus from '@lucide/svelte/icons/plus';
import Pencil from '@lucide/svelte/icons/pencil';
@@ -56,9 +57,11 @@
let peerForm = $state<BgpPeerCreate & { bgp_speaker_id?: string | null }>({
neighbor: '',
remote_asn: 0,
bgp_speaker_id: null
bgp_speaker_id: null,
enabled: true
});
let peerSaving = $state(false);
let peerToggleId = $state<string | null>(null);
let peerDeleteTarget = $state<PeerRow | null>(null);
// --- Speakers ---
@@ -93,14 +96,31 @@
// --- Peer actions ---
function openPeerCreate() {
peerEdit = null;
peerForm = { neighbor: '', remote_asn: 0, bgp_speaker_id: null };
peerForm = { neighbor: '', remote_asn: 0, bgp_speaker_id: null, enabled: true };
peerDialog = true;
}
function openPeerEdit(p: PeerRow) {
peerEdit = p;
peerForm = { neighbor: p.neighbor, remote_asn: p.remote_asn ?? 0, bgp_speaker_id: p.bgp_speaker_id };
peerForm = {
neighbor: p.neighbor,
remote_asn: p.remote_asn ?? 0,
bgp_speaker_id: p.bgp_speaker_id,
enabled: p.enabled !== false
};
peerDialog = true;
}
async function setPeerEnabled(p: PeerRow, enabled: boolean) {
peerToggleId = p.id;
try {
await apiMutate(`/v1/peers/${p.id}`, 'PATCH', { enabled });
toast.success(enabled ? 'Пир включён' : 'Пир отключён');
await loadAll();
} catch (e) {
toast.error(e instanceof Error ? e.message : String(e));
} finally {
peerToggleId = null;
}
}
async function savePeer() {
if (!peerForm.neighbor || !peerForm.remote_asn) {
toast.error('Укажите адрес и ASN');
@@ -112,8 +132,10 @@
await apiMutate(`/v1/peers/${peerEdit.id}`, 'PATCH', peerForm);
toast.success('Пир обновлён');
} else {
// API: omitted "enabled" decodes as false in Go; default new peers to enabled.
await apiMutate('/v1/peers', 'POST', { ...peerForm, enabled: true });
await apiMutate('/v1/peers', 'POST', {
...peerForm,
enabled: peerForm.enabled !== false
});
toast.success('Пир создан');
}
peerDialog = false;
@@ -218,6 +240,7 @@
<TableRow>
<TableHead>Адрес</TableHead>
<TableHead>Remote ASN</TableHead>
<TableHead class="w-[4.5rem] text-center">Вкл.</TableHead>
<TableHead>Состояние сессии</TableHead>
<TableHead>Спикер</TableHead>
<TableHead class="w-20"></TableHead>
@@ -228,6 +251,14 @@
<TableRow>
<TableCell class="font-mono">{p.neighbor}</TableCell>
<TableCell class="font-mono">{p.remote_asn ?? '—'}</TableCell>
<TableCell class="text-center">
<Switch
size="sm"
checked={p.enabled !== false}
disabled={peersLoading || peerToggleId === p.id}
onCheckedChange={(v) => setPeerEnabled(p, v)}
/>
</TableCell>
<TableCell>
<Badge variant={sessionBadge(p.session_state)}>{p.session_state || '—'}</Badge>
</TableCell>
@@ -241,7 +272,7 @@
</TableRow>
{:else}
<TableRow>
<TableCell colspan={5} class="text-muted-foreground text-center py-8">
<TableCell colspan={6} class="text-muted-foreground text-center py-8">
{peersLoading ? 'Загрузка…' : 'Нет пиров.'}
</TableCell>
</TableRow>
@@ -328,6 +359,24 @@
<Label for="p-speaker">Спикер (ID, опционально)</Label>
<Input id="p-speaker" placeholder="speaker-id" bind:value={peerForm.bgp_speaker_id} />
</div>
<div
class="border-border bg-muted/30 flex flex-row items-center justify-between gap-4 rounded-lg border p-3"
>
<div class="grid min-w-0 flex-1 gap-1 pr-2">
<Label for="p-enabled" class="text-foreground leading-snug">Включён</Label>
<p class="text-muted-foreground text-xs leading-snug">
Выключенный пир не попадает в конфиг BIRD до следующей ревизии.
</p>
</div>
<Switch
id="p-enabled"
class="shrink-0"
checked={peerForm.enabled !== false}
onCheckedChange={(v) => {
peerForm = { ...peerForm, enabled: v };
}}
/>
</div>
</div>
<DialogFooter>
<Button variant="outline" onclick={() => (peerDialog = false)}>Отмена</Button>