CI / changes (push) Successful in 11s
CI / commitlint (push) Has been skipped
CI / openapi (push) Has been skipped
CI / web (push) Successful in 1m3s
CI / go (push) Has been skipped
CI / bird2 (push) Has been skipped
CI / release (push) Successful in 4m4s
Updated the ModuleDetailComponent to include new queries for communities and DoH profiles, improving data handling. Added a module type alert function for better user guidance and refined the UI to display module type in a more user-friendly manner. Removed unused components and streamlined the refresh functionality for better performance.
117 lines
3.6 KiB
TypeScript
117 lines
3.6 KiB
TypeScript
import { useEffect, useState } from 'react'
|
||
import { toast } from 'sonner'
|
||
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogDescription,
|
||
DialogFooter,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
} from '@evobgp/ui/components/dialog'
|
||
import { Input } from '@evobgp/ui/components/input'
|
||
import { Label } from '@evobgp/ui/components/label'
|
||
|
||
import { LoadingButton } from '@/components/loading-button'
|
||
import { CommunitySelect } from '@/components/modules/community-select'
|
||
import { ApiError, apiMutate } from '@/lib/api-client'
|
||
import type { AsEntry, AsEntryCreate, AsEntryPatch, BgpCommunity } from '@/types/api'
|
||
|
||
interface ModuleAsEntryDialogProps {
|
||
open: boolean
|
||
moduleId: string
|
||
edit: AsEntry | null
|
||
communities: BgpCommunity[]
|
||
onOpenChange: (open: boolean) => void
|
||
onSaved: () => void | Promise<void>
|
||
}
|
||
|
||
export function ModuleAsEntryDialog({
|
||
open,
|
||
moduleId,
|
||
edit,
|
||
communities,
|
||
onOpenChange,
|
||
onSaved,
|
||
}: ModuleAsEntryDialogProps) {
|
||
const [saving, setSaving] = useState(false)
|
||
const [form, setForm] = useState<AsEntryCreate>({ asn: 0, community_id: null })
|
||
|
||
useEffect(() => {
|
||
if (!open) return
|
||
setForm(
|
||
edit
|
||
? { asn: edit.asn, community_id: edit.community_id }
|
||
: { asn: 0, community_id: null },
|
||
)
|
||
}, [open, edit])
|
||
|
||
async function save() {
|
||
const asn = Number(form.asn)
|
||
if (!Number.isFinite(asn) || asn < 1 || asn > 4294967295) {
|
||
toast.error('Укажите корректный ASN (1–4294967295)')
|
||
return
|
||
}
|
||
setSaving(true)
|
||
try {
|
||
const body: AsEntryCreate | AsEntryPatch = { asn, community_id: form.community_id }
|
||
if (edit) {
|
||
await apiMutate(`/v1/modules/${moduleId}/as-entries/${edit.id}`, 'PATCH', body)
|
||
toast.success('Запись обновлена')
|
||
} else {
|
||
await apiMutate(`/v1/modules/${moduleId}/as-entries`, 'POST', body as AsEntryCreate)
|
||
toast.success('Запись добавлена')
|
||
}
|
||
onOpenChange(false)
|
||
await onSaved()
|
||
} catch (e) {
|
||
toast.error(e instanceof ApiError ? e.message : String(e))
|
||
} finally {
|
||
setSaving(false)
|
||
}
|
||
}
|
||
|
||
return (
|
||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||
<DialogContent className="sm:max-w-sm">
|
||
<DialogHeader>
|
||
<DialogTitle>{edit ? 'Редактировать запись' : 'Новая AS-запись'}</DialogTitle>
|
||
<DialogDescription>
|
||
Номер автономной системы и community для политики анонса.
|
||
</DialogDescription>
|
||
</DialogHeader>
|
||
<div className="space-y-4 py-2">
|
||
<div className="flex flex-col gap-1.5">
|
||
<Label htmlFor="as-asn">ASN</Label>
|
||
<Input
|
||
id="as-asn"
|
||
type="number"
|
||
placeholder="12345"
|
||
value={form.asn || ''}
|
||
min={1}
|
||
max={4294967295}
|
||
onChange={(e) => setForm((s) => ({ ...s, asn: Number(e.target.value) }))}
|
||
/>
|
||
</div>
|
||
<CommunitySelect
|
||
id="as-comm"
|
||
label="Community"
|
||
value={form.community_id ?? null}
|
||
onValueChange={(v) => setForm((s) => ({ ...s, community_id: v }))}
|
||
communities={communities}
|
||
nullable
|
||
/>
|
||
</div>
|
||
<DialogFooter>
|
||
<LoadingButton variant="outline" onClick={() => onOpenChange(false)}>
|
||
Отмена
|
||
</LoadingButton>
|
||
<LoadingButton loading={saving} onClick={() => void save()}>
|
||
{edit ? 'Сохранить' : 'Добавить'}
|
||
</LoadingButton>
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
)
|
||
}
|