fix(api): сохранять достоверные параметры рекурсивных маршрутов

This commit is contained in:
Denozordec committed 2026-09-30 22:08:22 +07:00
1 parent 50fad3ac80
commit 54ef752a5b
17 files changed
+198 -45

No files matched your search

+11 -10
View File
@@ -7,7 +7,6 @@ import { PageHeader } from "@/components/page-header"
import {
RecursiveRoutesDataGrid,
type RecursiveRouteGroup,
inferCountry,
} from "@/components/data-grids/recursive-routes-data-grid"
import { FormField, SectionTitle } from "@/components/form-kit"
import { DataPageCard } from "@/components/data-page-card"
@@ -47,7 +46,7 @@ interface GatewayOption {
id: string
name: string
ip: string
status: "up" | "down"
status: "active" | "inactive" | "unknown"
}
const COUNTRY_OPTIONS = [
@@ -100,6 +99,7 @@ interface RouteForm {
interface RouteEndpointForm {
id: string
disabled: boolean
gateway: string
distance: number
scope: number | null
@@ -110,6 +110,7 @@ interface RouteEndpointForm {
const newEndpoint = (): RouteEndpointForm => ({
id: `ep-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
disabled: false,
gateway: "",
distance: 1,
scope: null,
@@ -241,7 +242,7 @@ function RouteSheet({
<div key={ep.id} className="rounded-lg border border-border bg-muted/20 p-3 flex flex-col gap-3">
<div className="flex items-center justify-between">
<span className="text-xs font-semibold text-muted-foreground uppercase tracking-wide">
Endpoint {idx + 1}
Endpoint {idx + 1}{ep.disabled ? " · отключён" : ""}
</span>
<button
type="button"
@@ -282,7 +283,6 @@ function RouteSheet({
{gateways.map((g) => {
const value = `${g.ip}%${g.name}`
const selected = ep.gateway === value
const country = inferCountry(g.name)
return (
<button
key={`${ep.id}-${g.id}`}
@@ -296,9 +296,9 @@ function RouteSheet({
)}
>
<div className="flex items-center gap-2">
<span className={cn("size-1.5 rounded-full shrink-0", g.status === "up" ? "bg-emerald-500" : "bg-red-500")} />
{country && <Flag code={country} className="shrink-0" />}
<span className={cn("size-1.5 rounded-full shrink-0", g.status === "active" ? "bg-success" : "bg-muted-foreground")} />
<span className="font-mono text-xs font-semibold flex-1 truncate">{g.name}</span>
<span className="text-xs text-muted-foreground">{g.status === "active" ? "Активный маршрут" : g.status === "inactive" ? "Неактивный маршрут" : "Статус неизвестен"}</span>
{selected && <CheckIcon className="size-3.5 text-primary shrink-0" />}
</div>
<div className="mt-1.5 grid grid-cols-[auto_auto_1fr] items-start gap-2 text-[11px] text-muted-foreground font-mono">
@@ -466,7 +466,7 @@ function RecursiveRoutesContent({ mode, backendUrl, context, patchUrl, beginWrit
const epoch = ++readEpoch.current
setOpError(null); setBusy("load"); setLiveStale(true)
try {
const parsed = recursiveReadSchema.safeParse(await apiFetch<unknown>(`/api/recursive-routes?serverId=${encodeURIComponent(selectedServerId)}`))
const parsed = recursiveReadSchema.safeParse(await apiFetch<unknown>(`/api/recursive-routes/catalog?serverId=${encodeURIComponent(selectedServerId)}`))
if (!parsed.success) throw new Error("Некорректный снимок маршрутов в ответе API")
const res = parsed.data
if (String(res.serverId) !== selectedServerId) throw new Error("Маршруты принадлежат другому устройству")
@@ -486,7 +486,7 @@ function RecursiveRoutesContent({ mode, backendUrl, context, patchUrl, beginWrit
if (!isLive || !liveServerListReady || !selectedServerId || context.error || !servers.some(s => s.id === selectedServerId)) return
const epoch = ++gatewayEpoch.current
try {
const parsed = recursiveGatewaysSchema.safeParse(await apiFetch<unknown>(`/api/recursive-routes/gateways?serverId=${encodeURIComponent(selectedServerId)}`))
const parsed = recursiveGatewaysSchema.safeParse(await apiFetch<unknown>(`/api/recursive-routes/gateways/catalog?serverId=${encodeURIComponent(selectedServerId)}`))
if (!parsed.success) throw new Error("Некорректный список шлюзов в ответе API")
const res = parsed.data
if (String(res.serverId) !== selectedServerId) throw new Error("Шлюзы принадлежат другому устройству")
@@ -596,6 +596,7 @@ function RecursiveRoutesContent({ mode, backendUrl, context, patchUrl, beginWrit
comment: group.comment,
endpoints: endpoints.map(ep => ({
id: ep.id,
disabled: ep.disabled,
gateway: ep.gateway,
distance: ep.distance,
scope: ep.scope,
@@ -617,8 +618,8 @@ function RecursiveRoutesContent({ mode, backendUrl, context, patchUrl, beginWrit
routingTable: v.routingTable,
checkGateway: ep.checkGateway,
comment: v.comment,
disabled: false,
country: ep.country || inferCountry(ep.gateway) || "",
disabled: ep.disabled,
country: ep.country || "",
})
let next: RecursiveRouteRow[]
if (sheetMode === "create") {