refactor: Simplify HealthCheckConfigFields component structure and enhance layout by integrating className prop for better styling flexibility, while maintaining functionality for load balancing and health check configurations
Build, Test, and Push CFDM Docker Image / test (push) Successful in 4m9s
Build, Test, and Push CFDM Docker Image / build-and-push (push) Successful in 2m18s
Build, Test, and Push CFDM Docker Image / update-wiki (push) Successful in 5s
Build, Test, and Push CFDM Docker Image / create-release (push) Has been skipped

This commit is contained in:
Denozordec
2026-06-25 19:06:01 +07:00
parent 0d652fa1c1
commit 5bdf4e774d
3 changed files with 143 additions and 157 deletions
@@ -10,6 +10,7 @@ import {
} from '@cfdm/ui/components/select'
import { Switch } from '@cfdm/ui/components/switch'
import { Label } from '@cfdm/ui/components/label'
import { cn } from '@cfdm/ui/lib/utils'
export type LbMode = 'round_robin' | 'failover' | 'weighted'
export type HealthCheckType = 'tcp' | 'http'
@@ -46,6 +47,7 @@ interface HealthCheckConfigFieldsProps {
lbModeOptions?: { value: string; label: string }[]
idPrefix?: string
showLbMode?: boolean
className?: string
}
export function HealthCheckConfigFields({
@@ -55,13 +57,16 @@ export function HealthCheckConfigFields({
lbModeOptions = defaultLbModeOptions,
idPrefix = 'health',
showLbMode = true,
className,
}: HealthCheckConfigFieldsProps) {
function patch(next: Partial<LbAndHealthConfig>) {
onChange({ ...value, ...next })
}
const isHttp = value.type === 'http'
return (
<AppFieldGroup>
<div className={cn('flex flex-col gap-4', className)}>
{showLbMode && (
<FormFieldSimple label={lbModeLabel} htmlFor={`${idPrefix}-lb-mode`}>
<Select
@@ -95,99 +100,115 @@ export function HealthCheckConfigFields({
</div>
</FormFieldSimple>
<FormFieldSimple label="Тип проверки" htmlFor={`${idPrefix}-type`}>
<Select
value={value.type}
onValueChange={(v) => patch({ type: (v ?? 'tcp') as HealthCheckType })}
>
<SelectTrigger id={`${idPrefix}-type`} className="w-full">
<SelectValue placeholder="Тип" />
</SelectTrigger>
<SelectContent>
{healthCheckTypes.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
</FormFieldSimple>
{value.enabled && (
<div className="rounded-md border border-border bg-muted/30 p-4">
<p className="mb-3 text-sm font-medium text-foreground">
Параметры проверки
</p>
<AppFieldGroup>
<FormFieldSimple label="Тип проверки" htmlFor={`${idPrefix}-type`}>
<Select
value={value.type}
onValueChange={(v) => patch({ type: (v ?? 'tcp') as HealthCheckType })}
>
<SelectTrigger id={`${idPrefix}-type`} className="w-full">
<SelectValue placeholder="Тип" />
</SelectTrigger>
<SelectContent>
{healthCheckTypes.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
</FormFieldSimple>
<FormFieldSimple label="Порт" htmlFor={`${idPrefix}-port`}>
<AppInput
id={`${idPrefix}-port`}
type="number"
inputMode="numeric"
placeholder="80"
value={value.port ?? ''}
onChange={(e) =>
patch({ port: e.target.value === '' ? null : Number(e.target.value) })
}
/>
</FormFieldSimple>
<FormFieldSimple label="Порт" htmlFor={`${idPrefix}-port`}>
<AppInput
id={`${idPrefix}-port`}
type="number"
inputMode="numeric"
placeholder="80"
value={value.port ?? ''}
onChange={(e) =>
patch({ port: e.target.value === '' ? null : Number(e.target.value) })
}
/>
</FormFieldSimple>
<FormFieldSimple label="HTTP path (для типа HTTP)" htmlFor={`${idPrefix}-path`}>
<AppInput
id={`${idPrefix}-path`}
placeholder="/health"
value={value.path ?? ''}
onChange={(e) =>
patch({ path: e.target.value === '' ? null : e.target.value })
}
/>
</FormFieldSimple>
{isHttp && (
<FormFieldSimple
label="HTTP path"
htmlFor={`${idPrefix}-path`}
>
<AppInput
id={`${idPrefix}-path`}
placeholder="/health"
value={value.path ?? ''}
onChange={(e) =>
patch({ path: e.target.value === '' ? null : e.target.value })
}
/>
</FormFieldSimple>
)}
<FormFieldSimple
label="Ожидаемый HTTP-статус"
htmlFor={`${idPrefix}-status`}
>
<AppInput
id={`${idPrefix}-status`}
type="number"
inputMode="numeric"
placeholder="200"
value={value.expected_status ?? ''}
onChange={(e) =>
patch({
expected_status:
e.target.value === '' ? null : Number(e.target.value),
})
}
/>
</FormFieldSimple>
{isHttp && (
<FormFieldSimple
label="Ожидаемый HTTP-статус"
htmlFor={`${idPrefix}-status`}
>
<AppInput
id={`${idPrefix}-status`}
type="number"
inputMode="numeric"
placeholder="200"
value={value.expected_status ?? ''}
onChange={(e) =>
patch({
expected_status:
e.target.value === '' ? null : Number(e.target.value),
})
}
/>
</FormFieldSimple>
)}
<div className="grid grid-cols-2 gap-4">
<FormFieldSimple label="Интервал, сек" htmlFor={`${idPrefix}-interval`}>
<AppInput
id={`${idPrefix}-interval`}
type="number"
inputMode="numeric"
placeholder="30"
value={value.interval_sec}
onChange={(e) =>
patch({
interval_sec:
e.target.value === '' ? 30 : Number(e.target.value),
})
}
/>
</FormFieldSimple>
<FormFieldSimple label="Таймаут, мс" htmlFor={`${idPrefix}-timeout`}>
<AppInput
id={`${idPrefix}-timeout`}
type="number"
inputMode="numeric"
placeholder="3000"
value={value.timeout_ms}
onChange={(e) =>
patch({
timeout_ms:
e.target.value === '' ? 3000 : Number(e.target.value),
})
}
/>
</FormFieldSimple>
</div>
</AppFieldGroup>
<div className="grid grid-cols-2 gap-4">
<FormFieldSimple label="Интервал, сек" htmlFor={`${idPrefix}-interval`}>
<AppInput
id={`${idPrefix}-interval`}
type="number"
inputMode="numeric"
placeholder="30"
value={value.interval_sec}
onChange={(e) =>
patch({
interval_sec:
e.target.value === '' ? 30 : Number(e.target.value),
})
}
/>
</FormFieldSimple>
<FormFieldSimple label="Таймаут, мс" htmlFor={`${idPrefix}-timeout`}>
<AppInput
id={`${idPrefix}-timeout`}
type="number"
inputMode="numeric"
placeholder="3000"
value={value.timeout_ms}
onChange={(e) =>
patch({
timeout_ms:
e.target.value === '' ? 3000 : Number(e.target.value),
})
}
/>
</FormFieldSimple>
</div>
</AppFieldGroup>
</div>
)}
</div>
)
}
+18 -49
View File
@@ -295,12 +295,6 @@ export function ServiceEditSheet({
)
}
function handleBindingLbModeChange(index: number, lbMode: LbMode) {
setBindings((current) =>
current.map((item, i) => (i === index ? { ...item, lb_mode: lbMode } : item)),
)
}
function handleBindingMetaChange(
index: number,
ip: string,
@@ -604,54 +598,29 @@ export function ServiceEditSheet({
)}
{showLbBlock && (
<Accordion>
<Accordion defaultValue={[`lb-${index}`]}>
<AccordionItem value={`lb-${index}`}>
<AccordionTrigger>
Балансировка и Health-check (multi-A)
</AccordionTrigger>
<AccordionContent>
<AppFieldGroup>
<AppField>
<AppFieldLabel htmlFor={`binding-lb-mode-${index}`}>
Режим балансировки
</AppFieldLabel>
<Select
value={binding.lb_mode}
onValueChange={(value) =>
handleBindingLbModeChange(
index,
(value ?? 'round_robin') as LbMode,
)
}
>
<SelectTrigger id={`binding-lb-mode-${index}`} className="w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="round_robin">Round Robin</SelectItem>
<SelectItem value="failover">Failover (приоритет)</SelectItem>
<SelectItem value="weighted">Weighted (веса)</SelectItem>
</SelectContent>
</Select>
</AppField>
<HealthCheckConfigFields
value={{
lb_mode: binding.lb_mode,
enabled: binding.health.enabled,
type: binding.health.type,
port: binding.health.port,
path: binding.health.path,
expected_status: binding.health.expected_status,
interval_sec: binding.health.interval_sec,
timeout_ms: binding.health.timeout_ms,
}}
onChange={(next) =>
handleBindingHealthChange(index, next)
}
showLbMode={false}
idPrefix={`binding-${index}-health`}
/>
</AppFieldGroup>
<HealthCheckConfigFields
value={{
lb_mode: binding.lb_mode,
enabled: binding.health.enabled,
type: binding.health.type,
port: binding.health.port,
path: binding.health.path,
expected_status: binding.health.expected_status,
interval_sec: binding.health.interval_sec,
timeout_ms: binding.health.timeout_ms,
}}
onChange={(next) =>
handleBindingHealthChange(index, next)
}
lbModeLabel="Режим балансировки"
idPrefix={`binding-${index}-health`}
/>
</AccordionContent>
</AccordionItem>
</Accordion>
@@ -29,7 +29,6 @@ import {
AccordionItem,
AccordionTrigger,
} from '@cfdm/ui/components/accordion'
import { Separator } from '@cfdm/ui/components/separator'
const groupTypes = [
{ value: 'vpn', label: 'VPN' },
@@ -201,22 +200,19 @@ export function ServiceGroupEditSheet({
</AppFieldGroup>
{hasDomain && (
<>
<Separator />
<Accordion>
<AccordionItem value="lb-health">
<AccordionTrigger>Балансировка и Health-check</AccordionTrigger>
<AccordionContent>
<HealthCheckConfigFields
value={lbHealth}
onChange={setLbHealth}
lbModeLabel="Режим балансировки общего домена"
idPrefix="group-lb-health"
/>
</AccordionContent>
</AccordionItem>
</Accordion>
</>
<Accordion defaultValue={['lb-health']}>
<AccordionItem value="lb-health">
<AccordionTrigger>Балансировка и Health-check</AccordionTrigger>
<AccordionContent>
<HealthCheckConfigFields
value={lbHealth}
onChange={setLbHealth}
lbModeLabel="Режим балансировки общего домена"
idPrefix="group-lb-health"
/>
</AccordionContent>
</AccordionItem>
</Accordion>
)}
</FormSheet>
)