feat(api): enhance health check and DNS management
quality / commitlint (push) Skipped
CD / update-wiki (push) Successful in 7s
quality / changes (push) Successful in 8s
quality / docker-check (push) Skipped
quality / web (push) Successful in 1m9s
quality / api (push) Successful in 40s
CD / quality (push) Successful in 2m0s
CD / publish (push) Successful in 2m38s

- Added batch endpoint for health status queries to reduce the number of requests.
- Improved DNS record management with caching and invalidation mechanisms.
- Updated health check service to handle new configurations and improve performance.
- Refactored certificate service to utilize concurrency for checks, enhancing efficiency.
- Removed unused dependencies and optimized package configurations.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-09-03 16:16:41 +07:00
co-authored by Cursor
parent de3dbe8521
commit 1e9cc04a59
42 changed files with 6036 additions and 2836 deletions
@@ -14,7 +14,14 @@ import {
} from '@cfdm/ui/components/select'
import { Alert, AlertDescription, AlertTitle } from '@/components/reui/alert'
import { ConfirmDialog } from '@/components/confirm-dialog'
import { changeServiceDomain, domainsListQueryOptions } from '@/queries'
import {
changeServiceDomain,
domainKeys,
domainsListQueryOptions,
serviceBindingKeys,
serviceGroupKeys,
serviceKeys,
} from '@/queries'
interface ChangeDomainSheetProps {
open: boolean
@@ -70,7 +77,12 @@ export function ChangeDomainSheet({
}),
onSuccess: async (result: { message?: string }) => {
toast.success(result.message ?? 'Привязки перенесены')
await queryClient.invalidateQueries()
await Promise.all([
queryClient.invalidateQueries({ queryKey: serviceBindingKeys.all }),
queryClient.invalidateQueries({ queryKey: domainKeys.all }),
queryClient.invalidateQueries({ queryKey: serviceKeys.all }),
queryClient.invalidateQueries({ queryKey: serviceGroupKeys.all }),
])
setConfirmOpen(false)
onOpenChange(false)
},
+6 -2
View File
@@ -15,7 +15,7 @@ import {
SelectValue,
} from '@cfdm/ui/components/select'
import { Alert, AlertDescription, AlertTitle } from '@/components/reui/alert'
import { changeBindingIp, serviceNodesQueryOptions } from '@/queries'
import { changeBindingIp, serviceBindingKeys, serviceGroupKeys, serviceKeys, serviceNodesQueryOptions } from '@/queries'
interface ChangeIpSheetProps {
open: boolean
@@ -82,7 +82,11 @@ export function ChangeIpSheet({
onSuccess: async (result) => {
setPreview(result.message)
toast.success(result.message)
await queryClient.invalidateQueries()
await Promise.all([
queryClient.invalidateQueries({ queryKey: serviceBindingKeys.all }),
queryClient.invalidateQueries({ queryKey: serviceKeys.all }),
queryClient.invalidateQueries({ queryKey: serviceGroupKeys.all }),
])
onOpenChange(false)
},
onError: (e: unknown) =>
@@ -1,4 +1,4 @@
import { useMemo, useEffect, useRef } from 'react'
import { useMemo, useRef } from 'react'
import { Bar, BarChart, CartesianGrid, Cell, Pie, PieChart, XAxis } from 'recharts'
import { StatusBadge } from '@/components/status-badge'
@@ -18,34 +18,6 @@ import {
} from '@cfdm/ui/components/chart'
import { Separator } from '@cfdm/ui/components/separator'
import { cn } from '@cfdm/ui/lib/utils'
import { debugAgentLog } from '@/lib/debug-agent-log'
function useChartSizeLog(chartId: string, dataLen: number) {
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
const el = ref.current
if (!el) return
const svg = el.querySelector('svg.recharts-surface')
const chartSlot = el.querySelector('[data-slot=chart]') as HTMLElement | null
debugAgentLog(
'dashboard-analytics.tsx:chart-mount',
'chart container dimensions',
{
chartId,
dataLen,
containerW: el.clientWidth,
containerH: el.clientHeight,
chartSlotW: chartSlot?.clientWidth ?? 0,
chartSlotH: chartSlot?.clientHeight ?? 0,
svgW: svg?.getAttribute('width') ?? null,
svgH: svg?.getAttribute('height') ?? null,
hasSvg: Boolean(svg),
},
'D',
)
}, [chartId, dataLen])
return ref
}
const statusChartConfig = {
count: { label: 'Сертификаты' },
@@ -74,7 +46,7 @@ interface CertStatusChartProps {
}
export function CertStatusChart({ data }: CertStatusChartProps) {
const chartRef = useChartSizeLog('cert-status', data.length)
const chartRef = useRef<HTMLDivElement>(null)
const total = useMemo(
() => data.reduce((sum, entry) => sum + entry.count, 0),
[data],
@@ -166,7 +138,7 @@ interface GroupDomainsChartProps {
}
export function GroupDomainsChart({ data }: GroupDomainsChartProps) {
const chartRef = useChartSizeLog('group-domains', data.length)
const chartRef = useRef<HTMLDivElement>(null)
return (
<Frame dense spacing="sm" className="w-full">
@@ -1,4 +1,4 @@
import { useId, useMemo, useState } from 'react'
import { useId, useMemo, useRef, useState } from 'react'
import { ActivityIcon, InfoIcon, TrendingDownIcon, TrendingUpIcon } from 'lucide-react'
import { Area, ComposedChart, Line, XAxis, YAxis } from 'recharts'
@@ -259,13 +259,20 @@ export function UptimeChart({
})
: []
// rAF-throttled: mouse-move must not re-render the card on every pixel.
const rafRef = useRef(0)
function syncHover(state: {
activeTooltipIndex?: unknown
activeIndex?: unknown
}) {
const index = Number(state.activeTooltipIndex ?? state.activeIndex)
if (!Number.isFinite(index)) return
setHovered(points[index] ?? null)
const next = points[index] ?? null
if (rafRef.current) cancelAnimationFrame(rafRef.current)
rafRef.current = requestAnimationFrame(() => {
rafRef.current = 0
setHovered(next)
})
}
const panel = (
File diff suppressed because it is too large Load Diff