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
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:
@@ -123,6 +123,7 @@ export type PeerRow = {
|
|||||||
name?: string;
|
name?: string;
|
||||||
neighbor: string;
|
neighbor: string;
|
||||||
remote_asn?: number;
|
remote_asn?: number;
|
||||||
|
enabled?: boolean;
|
||||||
session_state: string;
|
session_state: string;
|
||||||
bgp_speaker_id: string | null;
|
bgp_speaker_id: string | null;
|
||||||
};
|
};
|
||||||
@@ -131,6 +132,7 @@ export type BgpPeerCreate = {
|
|||||||
neighbor: string;
|
neighbor: string;
|
||||||
remote_asn: number;
|
remote_asn: number;
|
||||||
bgp_speaker_id?: string | null;
|
bgp_speaker_id?: string | null;
|
||||||
|
enabled?: boolean;
|
||||||
};
|
};
|
||||||
export type BgpPeerPatch = Partial<BgpPeerCreate>;
|
export type BgpPeerPatch = Partial<BgpPeerCreate>;
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow
|
TableRow
|
||||||
} from '$lib/components/ui/table/index.js';
|
} from '$lib/components/ui/table/index.js';
|
||||||
|
import { Switch } from '$lib/components/ui/switch/index.js';
|
||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
import Plus from '@lucide/svelte/icons/plus';
|
import Plus from '@lucide/svelte/icons/plus';
|
||||||
import Pencil from '@lucide/svelte/icons/pencil';
|
import Pencil from '@lucide/svelte/icons/pencil';
|
||||||
@@ -56,9 +57,11 @@
|
|||||||
let peerForm = $state<BgpPeerCreate & { bgp_speaker_id?: string | null }>({
|
let peerForm = $state<BgpPeerCreate & { bgp_speaker_id?: string | null }>({
|
||||||
neighbor: '',
|
neighbor: '',
|
||||||
remote_asn: 0,
|
remote_asn: 0,
|
||||||
bgp_speaker_id: null
|
bgp_speaker_id: null,
|
||||||
|
enabled: true
|
||||||
});
|
});
|
||||||
let peerSaving = $state(false);
|
let peerSaving = $state(false);
|
||||||
|
let peerToggleId = $state<string | null>(null);
|
||||||
let peerDeleteTarget = $state<PeerRow | null>(null);
|
let peerDeleteTarget = $state<PeerRow | null>(null);
|
||||||
|
|
||||||
// --- Speakers ---
|
// --- Speakers ---
|
||||||
@@ -93,14 +96,31 @@
|
|||||||
// --- Peer actions ---
|
// --- Peer actions ---
|
||||||
function openPeerCreate() {
|
function openPeerCreate() {
|
||||||
peerEdit = null;
|
peerEdit = null;
|
||||||
peerForm = { neighbor: '', remote_asn: 0, bgp_speaker_id: null };
|
peerForm = { neighbor: '', remote_asn: 0, bgp_speaker_id: null, enabled: true };
|
||||||
peerDialog = true;
|
peerDialog = true;
|
||||||
}
|
}
|
||||||
function openPeerEdit(p: PeerRow) {
|
function openPeerEdit(p: PeerRow) {
|
||||||
peerEdit = p;
|
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;
|
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() {
|
async function savePeer() {
|
||||||
if (!peerForm.neighbor || !peerForm.remote_asn) {
|
if (!peerForm.neighbor || !peerForm.remote_asn) {
|
||||||
toast.error('Укажите адрес и ASN');
|
toast.error('Укажите адрес и ASN');
|
||||||
@@ -112,8 +132,10 @@
|
|||||||
await apiMutate(`/v1/peers/${peerEdit.id}`, 'PATCH', peerForm);
|
await apiMutate(`/v1/peers/${peerEdit.id}`, 'PATCH', peerForm);
|
||||||
toast.success('Пир обновлён');
|
toast.success('Пир обновлён');
|
||||||
} else {
|
} else {
|
||||||
// API: omitted "enabled" decodes as false in Go; default new peers to enabled.
|
await apiMutate('/v1/peers', 'POST', {
|
||||||
await apiMutate('/v1/peers', 'POST', { ...peerForm, enabled: true });
|
...peerForm,
|
||||||
|
enabled: peerForm.enabled !== false
|
||||||
|
});
|
||||||
toast.success('Пир создан');
|
toast.success('Пир создан');
|
||||||
}
|
}
|
||||||
peerDialog = false;
|
peerDialog = false;
|
||||||
@@ -218,6 +240,7 @@
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>Адрес</TableHead>
|
<TableHead>Адрес</TableHead>
|
||||||
<TableHead>Remote ASN</TableHead>
|
<TableHead>Remote ASN</TableHead>
|
||||||
|
<TableHead class="w-[4.5rem] text-center">Вкл.</TableHead>
|
||||||
<TableHead>Состояние сессии</TableHead>
|
<TableHead>Состояние сессии</TableHead>
|
||||||
<TableHead>Спикер</TableHead>
|
<TableHead>Спикер</TableHead>
|
||||||
<TableHead class="w-20"></TableHead>
|
<TableHead class="w-20"></TableHead>
|
||||||
@@ -228,6 +251,14 @@
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell class="font-mono">{p.neighbor}</TableCell>
|
<TableCell class="font-mono">{p.neighbor}</TableCell>
|
||||||
<TableCell class="font-mono">{p.remote_asn ?? '—'}</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>
|
<TableCell>
|
||||||
<Badge variant={sessionBadge(p.session_state)}>{p.session_state || '—'}</Badge>
|
<Badge variant={sessionBadge(p.session_state)}>{p.session_state || '—'}</Badge>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
@@ -241,7 +272,7 @@
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
{:else}
|
{:else}
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colspan={5} class="text-muted-foreground text-center py-8">
|
<TableCell colspan={6} class="text-muted-foreground text-center py-8">
|
||||||
{peersLoading ? 'Загрузка…' : 'Нет пиров.'}
|
{peersLoading ? 'Загрузка…' : 'Нет пиров.'}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -328,6 +359,24 @@
|
|||||||
<Label for="p-speaker">Спикер (ID, опционально)</Label>
|
<Label for="p-speaker">Спикер (ID, опционально)</Label>
|
||||||
<Input id="p-speaker" placeholder="speaker-id" bind:value={peerForm.bgp_speaker_id} />
|
<Input id="p-speaker" placeholder="speaker-id" bind:value={peerForm.bgp_speaker_id} />
|
||||||
</div>
|
</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>
|
</div>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button variant="outline" onclick={() => (peerDialog = false)}>Отмена</Button>
|
<Button variant="outline" onclick={() => (peerDialog = false)}>Отмена</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user