feat:Update pnpm-lock.yaml to link shared package; modify API routes to utilize new schemas for domain and service management; enhance DNS record handling with CNAME support; refactor service and subdomain routes for improved functionality; implement confirm dialog for domain deletion in the frontend; clean up unused components and improve UI consistency.
Build, Test, and Push CFDM Docker Image / test (push) Failing after 51s
Build, Test, and Push CFDM Docker Image / build-and-push (push) Has been skipped
Build, Test, and Push CFDM Docker Image / update-wiki (push) Has been skipped
Build, Test, and Push CFDM Docker Image / create-release (push) Has been skipped
Build, Test, and Push CFDM Docker Image / test (push) Failing after 51s
Build, Test, and Push CFDM Docker Image / build-and-push (push) Has been skipped
Build, Test, and Push CFDM Docker Image / update-wiki (push) Has been skipped
Build, Test, and Push CFDM Docker Image / create-release (push) Has been skipped
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import type { CertMonitoring } from '@cfdm/shared'
|
||||
import type { ServiceView, SubdomainRecord } from '@/lib/schemas'
|
||||
import { certMonitoringOptions } from '@/lib/cert-monitoring'
|
||||
import { formatServiceGroupLabel } from '@/lib/service-utils'
|
||||
import { Button } from '@cfdm/ui/components/button'
|
||||
import { Input } from '@cfdm/ui/components/input'
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
} from '@cfdm/ui/components/field'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@cfdm/ui/components/select'
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
} from '@cfdm/ui/components/sheet'
|
||||
import { Spinner } from '@cfdm/ui/components/spinner'
|
||||
|
||||
export interface SubdomainEditValues {
|
||||
name: string
|
||||
serviceId: string
|
||||
certMonitoring: CertMonitoring
|
||||
}
|
||||
|
||||
interface SubdomainEditSheetProps {
|
||||
mode: 'create' | 'edit'
|
||||
subdomain: SubdomainRecord | null
|
||||
zoneName: string
|
||||
services: ServiceView[]
|
||||
serviceGroupById: Map<number, string | null>
|
||||
currentServiceId: string
|
||||
open: boolean
|
||||
isSaving: boolean
|
||||
onOpenChange: (open: boolean) => void
|
||||
onSubmit: (values: SubdomainEditValues) => void
|
||||
}
|
||||
|
||||
export function SubdomainEditSheet({
|
||||
mode,
|
||||
subdomain,
|
||||
zoneName,
|
||||
services,
|
||||
serviceGroupById,
|
||||
currentServiceId,
|
||||
open,
|
||||
isSaving,
|
||||
onOpenChange,
|
||||
onSubmit,
|
||||
}: SubdomainEditSheetProps) {
|
||||
const [name, setName] = useState('')
|
||||
const [serviceId, setServiceId] = useState('none')
|
||||
const [certMonitoring, setCertMonitoring] = useState<CertMonitoring>('auto')
|
||||
|
||||
const serviceItems = useMemo(
|
||||
() => [
|
||||
{ label: 'Без сервиса', value: 'none' },
|
||||
...services.map((service) => ({
|
||||
label: formatServiceGroupLabel(
|
||||
serviceGroupById.get(service.id),
|
||||
service.name,
|
||||
),
|
||||
value: String(service.id),
|
||||
})),
|
||||
],
|
||||
[services, serviceGroupById],
|
||||
)
|
||||
|
||||
const certMonitoringItems = useMemo(
|
||||
() =>
|
||||
certMonitoringOptions.map((option) => ({
|
||||
label: option.label,
|
||||
value: option.value,
|
||||
})),
|
||||
[],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return
|
||||
if (mode === 'edit' && subdomain) {
|
||||
setName(subdomain.name)
|
||||
setServiceId(currentServiceId || 'none')
|
||||
setCertMonitoring(subdomain.cert_monitoring)
|
||||
return
|
||||
}
|
||||
setName('')
|
||||
setServiceId('none')
|
||||
setCertMonitoring('auto')
|
||||
}, [open, mode, subdomain, currentServiceId])
|
||||
|
||||
function handleSubmit(event: React.FormEvent) {
|
||||
event.preventDefault()
|
||||
const trimmed = name.trim()
|
||||
if (!trimmed) return
|
||||
onSubmit({ name: trimmed, serviceId, certMonitoring })
|
||||
}
|
||||
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={onOpenChange}>
|
||||
<SheetContent>
|
||||
<SheetHeader>
|
||||
<SheetTitle>
|
||||
{mode === 'create' ? 'Создать поддомен' : 'Редактировать поддомен'}
|
||||
</SheetTitle>
|
||||
<SheetDescription>
|
||||
{mode === 'create'
|
||||
? `Имя записи в зоне ${zoneName} (например, www или api)`
|
||||
: `Изменение поддомена в зоне ${zoneName}`}
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
<form onSubmit={handleSubmit} className="flex flex-col gap-4 px-4">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="subdomain_name">Имя</FieldLabel>
|
||||
<Input
|
||||
id="subdomain_name"
|
||||
placeholder="www"
|
||||
value={name}
|
||||
onChange={(event) => setName(event.target.value)}
|
||||
className="font-mono"
|
||||
/>
|
||||
</Field>
|
||||
{mode === 'edit' && (
|
||||
<>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="subdomain_service">Сервис</FieldLabel>
|
||||
<Select
|
||||
items={serviceItems}
|
||||
value={serviceId}
|
||||
onValueChange={(value) => setServiceId(value ?? 'none')}
|
||||
>
|
||||
<SelectTrigger id="subdomain_service" className="w-full">
|
||||
<SelectValue placeholder="Без сервиса" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{serviceItems.map((item) => (
|
||||
<SelectItem key={item.value} value={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="subdomain_cert_monitoring">
|
||||
Мониторинг SSL
|
||||
</FieldLabel>
|
||||
<Select
|
||||
items={certMonitoringItems}
|
||||
value={certMonitoring}
|
||||
onValueChange={(value) =>
|
||||
setCertMonitoring((value ?? 'auto') as CertMonitoring)
|
||||
}
|
||||
>
|
||||
<SelectTrigger id="subdomain_cert_monitoring" className="w-full">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{certMonitoringOptions.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FieldDescription>
|
||||
{
|
||||
certMonitoringOptions.find((o) => o.value === certMonitoring)
|
||||
?.description
|
||||
}
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</>
|
||||
)}
|
||||
</FieldGroup>
|
||||
<SheetFooter>
|
||||
<Button type="submit" disabled={isSaving || !name.trim()} className="w-full">
|
||||
{isSaving && <Spinner data-icon="inline-start" />}
|
||||
{isSaving
|
||||
? 'Сохранение…'
|
||||
: mode === 'create'
|
||||
? 'Создать'
|
||||
: 'Сохранить'}
|
||||
</Button>
|
||||
</SheetFooter>
|
||||
</form>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user