CI / changes (push) Successful in 10s
CI / commitlint (push) Has been skipped
CI / openapi (push) Has been skipped
CI / web (push) Successful in 50s
CI / go (push) Has been skipped
CI / bird2 (push) Has been skipped
CI / release (push) Successful in 3m58s
Updated multiple components to utilize the new FormDrawer for modal dialogs, enhancing the user interface and streamlining the layout. This change includes the ConfirmDialog, ApiKeyCreateDialog, FirewallRuleCreateDialog, and others, ensuring a more cohesive and modern design across the application. Additionally, refactored the ConfirmDialog to improve confirmation handling and user feedback during actions.
110 lines
3.1 KiB
TypeScript
110 lines
3.1 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import { toast } from 'sonner'
|
|
|
|
import { Button } from '@evobgp/ui/components/button'
|
|
import { Input } from '@evobgp/ui/components/input'
|
|
import { Label } from '@evobgp/ui/components/label'
|
|
|
|
import { FormDrawer } from '@/components/form-drawer'
|
|
import { LoadingButton } from '@/components/loading-button'
|
|
import { SelectField } from '@/components/select-field'
|
|
import { API_KEY_ROLE_ITEMS } from '@/lib/access/api-key-labels'
|
|
import { useCreateApiKeyMutation } from '@/queries/api-keys'
|
|
import type { ApiKeyCreate, ApiKeyCreated, ApiKeyRole } from '@/types/api'
|
|
|
|
interface ApiKeyCreateDialogProps {
|
|
open: boolean
|
|
onOpenChange: (open: boolean) => void
|
|
onCreated: (created: ApiKeyCreated) => void
|
|
}
|
|
|
|
export function ApiKeyCreateDialog({ open, onOpenChange, onCreated }: ApiKeyCreateDialogProps) {
|
|
const createMutation = useCreateApiKeyMutation()
|
|
const [name, setName] = useState('')
|
|
const [role, setRole] = useState<ApiKeyRole>('editor')
|
|
const [expiresLocal, setExpiresLocal] = useState('')
|
|
|
|
useEffect(() => {
|
|
if (!open) return
|
|
setName('')
|
|
setRole('editor')
|
|
setExpiresLocal('')
|
|
}, [open])
|
|
|
|
function handleOpenChange(next: boolean) {
|
|
onOpenChange(next)
|
|
}
|
|
|
|
async function save() {
|
|
if (!name.trim()) {
|
|
toast.error('Укажите имя')
|
|
return
|
|
}
|
|
const body: ApiKeyCreate = {
|
|
name: name.trim(),
|
|
role,
|
|
}
|
|
if (expiresLocal.trim()) {
|
|
const d = new Date(expiresLocal)
|
|
if (Number.isNaN(d.getTime())) {
|
|
toast.error('Некорректная дата истечения')
|
|
return
|
|
}
|
|
body.expires_at = d.toISOString()
|
|
}
|
|
try {
|
|
const created = await createMutation.mutateAsync(body)
|
|
onOpenChange(false)
|
|
onCreated(created)
|
|
} catch {
|
|
// toast handled in mutation
|
|
}
|
|
}
|
|
|
|
return (
|
|
<FormDrawer
|
|
open={open}
|
|
onOpenChange={handleOpenChange}
|
|
title="Новый API-ключ"
|
|
className="sm:max-w-sm"
|
|
footer={
|
|
<>
|
|
<Button variant="outline" onClick={() => handleOpenChange(false)}>
|
|
Отмена
|
|
</Button>
|
|
<LoadingButton onClick={save} loading={createMutation.isPending}>
|
|
Создать
|
|
</LoadingButton>
|
|
</>
|
|
}
|
|
>
|
|
<div className="flex flex-col gap-2">
|
|
<Label htmlFor="key-name">Имя</Label>
|
|
<Input
|
|
id="key-name"
|
|
value={name}
|
|
onChange={(e) => setName(e.target.value)}
|
|
placeholder="CI / оператор UI"
|
|
/>
|
|
</div>
|
|
<SelectField
|
|
id="key-role"
|
|
label="Роль"
|
|
items={[...API_KEY_ROLE_ITEMS]}
|
|
value={role}
|
|
placeholder="Выберите роль"
|
|
onValueChange={(v) => v && setRole(v as ApiKeyRole)}
|
|
/>
|
|
<div className="flex flex-col gap-2">
|
|
<Label htmlFor="key-expires">Истекает (опционально)</Label>
|
|
<Input
|
|
id="key-expires"
|
|
type="datetime-local"
|
|
value={expiresLocal}
|
|
onChange={(e) => setExpiresLocal(e.target.value)}
|
|
/>
|
|
</div>
|
|
</FormDrawer>
|
|
)
|
|
}
|