Files
cloudflare-domain-manager/apps/web/src/components/service-group-edit-sheet.tsx
T
Denozordec 50c5c21c18
quality / commitlint (push) Skipped
CD / update-wiki (push) Successful in 6s
quality / changes (push) Successful in 5s
quality / api (push) Skipped
quality / docker-check (push) Skipped
quality / web (push) Successful in 52s
CD / quality (push) Successful in 1m1s
CD / publish (push) Successful in 1m36s
feat(services): enhance service edit and display components with common domain support
- Added a common FQDN input field in the ServiceEditSheet to streamline domain management for services.
- Updated binding handling to synchronize the common domain across service bindings.
- Improved the ServiceKanbanCard to display both common domain and IP addresses for better visibility.
- Refactored the ServiceFqdnList to support customizable text classes and added a new ServiceIpList component for IP display.

This commit enhances the user experience by simplifying domain management and improving the display of service information.
2026-08-19 13:29:15 +07:00

150 lines
4.2 KiB
TypeScript

import { useEffect } from 'react'
import { useForm, Controller } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import {
createServiceGroupSchema,
type CreateServiceGroupInput,
type ServiceGroup,
} from '@/lib/schemas'
import type { z } from 'zod'
import { FormSheet } from '@/components/form-sheet'
import { FormFieldSimple } from '@/components/form-field'
import { LoadingButton } from '@/components/loading-button'
import { AppFieldGroup } from '@/components/app-field'
import { AppInput } from '@/components/app-input'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@cfdm/ui/components/select'
const groupTypes = [
{ value: 'vpn', label: 'VPN' },
{ value: 'network', label: 'Сеть' },
{ value: 'internet', label: 'Интернет' },
{ value: 'bgp', label: 'BGP' },
{ value: 'custom', label: 'Другое' },
] as const
type ServiceGroupFormValues = z.input<typeof createServiceGroupSchema>
interface ServiceGroupEditSheetProps {
mode: 'create' | 'edit'
group: ServiceGroup | null
open: boolean
isSaving: boolean
onOpenChange: (open: boolean) => void
onCreate?: (body: CreateServiceGroupInput) => void
onSave?: (id: number, body: CreateServiceGroupInput) => void
}
export function ServiceGroupEditSheet({
mode,
group,
open,
isSaving,
onOpenChange,
onCreate,
onSave,
}: ServiceGroupEditSheetProps) {
const form = useForm<ServiceGroupFormValues>({
resolver: zodResolver(createServiceGroupSchema),
defaultValues: {
name: '',
type: 'custom',
domain: null,
},
})
useEffect(() => {
if (!open) return
if (mode === 'edit' && group) {
form.reset({
name: group.name,
type: group.type,
domain: null,
})
} else {
form.reset({ name: '', type: 'custom', domain: null })
}
}, [open, mode, group, form])
function handleSubmit(values: ServiceGroupFormValues) {
const body: CreateServiceGroupInput = {
name: values.name,
type: values.type ?? 'custom',
icon: values.icon,
domain: null,
}
if (mode === 'create') {
onCreate?.(body)
} else if (group) {
onSave?.(group.id, body)
}
}
return (
<FormSheet<ServiceGroupFormValues>
open={open}
onOpenChange={onOpenChange}
title={mode === 'create' ? 'Новая группа сервисов' : 'Редактировать группу'}
description="Группа нужна только для сортировки каталога. Общий домен и IP задаются у каждого сервиса."
form={form}
onSubmit={handleSubmit}
contentClassName="gap-6"
footer={
<LoadingButton
type="submit"
className="w-full"
isLoading={isSaving}
loadingLabel="Сохранение…"
>
{mode === 'create' ? 'Создать' : 'Сохранить'}
</LoadingButton>
}
>
<AppFieldGroup>
<FormFieldSimple
label="Название"
htmlFor="group-name"
error={form.formState.errors.name}
>
<AppInput
id="group-name"
placeholder="VPN"
{...form.register('name')}
aria-invalid={!!form.formState.errors.name}
/>
</FormFieldSimple>
<FormFieldSimple label="Тип" htmlFor="group-type">
<Controller
control={form.control}
name="type"
render={({ field }) => (
<Select
value={field.value}
onValueChange={(value) =>
field.onChange(value as CreateServiceGroupInput['type'])
}
>
<SelectTrigger id="group-type">
<SelectValue placeholder="Выберите тип" />
</SelectTrigger>
<SelectContent>
{groupTypes.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
)}
/>
</FormFieldSimple>
</AppFieldGroup>
</FormSheet>
)
}