fix(services): вернуть вес и приоритет в режиме балансировки
quality / commitlint (push) Skipped
CD / update-wiki (push) Successful in 6s
quality / changes (push) Successful in 8s
quality / api (push) Skipped
quality / docker-check (push) Skipped
quality / web (push) Successful in 54s
CD / quality (push) Successful in 1m5s
CD / publish (push) Successful in 1m43s

После объединения адресов в форме пропали per-IP поля. Weighted снова задаёт вес, failover — основной и запасной.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-08-20 17:06:29 +07:00
co-authored by Cursor
parent f5d97e463a
commit 8a13888db7
4 changed files with 192 additions and 1 deletions
@@ -17,7 +17,7 @@ import {
SelectValue,
} from '@cfdm/ui/components/select'
import { Switch } from '@cfdm/ui/components/switch'
import { FieldGroup } from '@cfdm/ui/components/field'
import { Field, FieldGroup, FieldLabel } from '@cfdm/ui/components/field'
import { Button } from '@cfdm/ui/components/button'
import { ButtonGroup } from '@cfdm/ui/components/button-group'
import { CableIcon, GlobeIcon } from 'lucide-react'
@@ -62,6 +62,11 @@ const defaultLbModeOptions = [
{ value: 'weighted', label: 'Weighted (веса)' },
]
export interface LbPoolMetaChange {
weight?: number
priority?: number
}
function CompactNumberField({
id,
value,
@@ -95,6 +100,89 @@ function CompactNumberField({
)
}
function PoolLbMetaFields({
idPrefix,
mode,
ips,
weights,
priorities,
onMetaChange,
}: {
idPrefix: string
mode: Exclude<LbMode, 'round_robin'>
ips: readonly string[]
weights: Record<string, number>
priorities: Record<string, number>
onMetaChange?: (ip: string, meta: LbPoolMetaChange) => void
}) {
const isWeighted = mode === 'weighted'
const minPriority =
ips.length === 0
? 1
: Math.min(...ips.map((ip) => priorities[ip] ?? 1))
return (
<SettingRow
title={isWeighted ? 'Вес IP' : 'Приоритет IP'}
description={
isWeighted
? 'Больше — чаще в пуле'
: '1 — основной, больше — запасной'
}
compact
stacked
className="gap-3 px-0 py-3"
contentClassName="min-w-0"
>
{ips.length === 0 ? (
<p className="text-muted-foreground text-sm">Сначала добавьте IP выше</p>
) : (
<div className="flex w-full flex-col gap-2">
{ips.map((ip) => {
const isPrimary = (priorities[ip] ?? 1) === minPriority
const fieldId = isWeighted
? `${idPrefix}-weight-${ip}`
: `${idPrefix}-priority-${ip}`
return (
<div key={ip} className="flex items-center gap-3">
<span className="min-w-0 flex-1 truncate font-mono text-sm">{ip}</span>
{!isWeighted ? (
<Badge
variant={isPrimary ? 'success-light' : 'outline'}
size="xs"
radius="full"
>
{isPrimary ? 'Основной' : 'Запасной'}
</Badge>
) : null}
<Field className="w-28 gap-0">
<FieldLabel htmlFor={fieldId} className="sr-only">
{isWeighted ? `Вес ${ip}` : `Приоритет ${ip}`}
</FieldLabel>
<CompactNumberField
id={fieldId}
value={isWeighted ? (weights[ip] ?? 1) : (priorities[ip] ?? 1)}
min={1}
max={100}
onValueChange={(next) =>
onMetaChange?.(
ip,
isWeighted
? { weight: next ?? 1 }
: { priority: next ?? 1 },
)
}
/>
</Field>
</div>
)
})}
</div>
)}
</SettingRow>
)
}
export function HealthCheckConfigFields({
value,
onChange,
@@ -102,6 +190,10 @@ export function HealthCheckConfigFields({
lbModeOptions = defaultLbModeOptions,
idPrefix = 'health',
showLbMode = true,
ips = [],
weights = {},
priorities = {},
onMetaChange,
className,
}: {
value: LbAndHealthConfig
@@ -110,6 +202,10 @@ export function HealthCheckConfigFields({
lbModeOptions?: { value: string; label: string }[]
idPrefix?: string
showLbMode?: boolean
ips?: readonly string[]
weights?: Record<string, number>
priorities?: Record<string, number>
onMetaChange?: (ip: string, meta: LbPoolMetaChange) => void
className?: string
}) {
function patch(next: Partial<LbAndHealthConfig>) {
@@ -153,6 +249,17 @@ export function HealthCheckConfigFields({
</SettingRow>
) : null}
{showLbMode && value.lb_mode !== 'round_robin' ? (
<PoolLbMetaFields
idPrefix={idPrefix}
mode={value.lb_mode}
ips={ips}
weights={weights}
priorities={priorities}
onMetaChange={onMetaChange}
/>
) : null}
<SettingRow
title="Провайдер health-check"
description="Кто пробирует цель. Можно выбрать несколько источников."
@@ -17,6 +17,7 @@ import {
DEFAULT_BINDING_HEALTH,
emptyAddressBlock,
hydrateAddressBlock,
patchAddressIpMeta,
toBindingDrafts,
toDomainsPayload,
type AddressBlockState,
@@ -282,6 +283,12 @@ export function ServiceEditSheet({
idPrefix="service-health"
value={primaryHealthValue}
onChange={handlePrimaryHealthChange}
ips={address.nodes.map((node) => node.ip)}
weights={address.target_ip_weights}
priorities={address.target_ip_priorities}
onMetaChange={(ip, meta) =>
setAddress((current) => patchAddressIpMeta(current, ip, meta))
}
/>
</section>
</div>