fix(probes): проверять расписание и сохранять подтверждённые данные

This commit is contained in:
Denozordec committed 2026-10-03 22:12:08 +07:00
1 parent 1d27127b52
commit 271291a910
10 files changed
+108 -98

No files matched your search

+7 -77
View File
@@ -15,10 +15,7 @@ import {
type SchedRule,
type SchedType,
} from "@/components/data-grids/probes-schedule-data-grid"
import {
ProbesSpeedProbesDataGrid,
type SpeedProbeApiRow,
} from "@/components/data-grids/probes-speed-probes-data-grid"
import {ProbesSpeedSchedule} from "@/components/probes-speed-schedule"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { ServerRailLayout, ServerRailMobileButton } from "@/components/server-rail-layout"
@@ -32,7 +29,7 @@ import {
PlayIcon, SquareIcon, CopyIcon, Trash2Icon, PlusIcon,
ActivityIcon, RouteIcon, SearchIcon, NetworkIcon, RulerIcon,
ZapIcon, CheckIcon, TerminalIcon,
LoaderCircleIcon, AlertCircleIcon,
LoaderCircleIcon,
} from "lucide-react"
import { cn } from "@/lib/utils"
import { requestJson } from "@/shared/api/http-client"
@@ -382,65 +379,6 @@ function TerminalOutput({ test }: { test: DiagTest }) {
}
// ─── uptime speed probes (live) ───────────────────────────────────────────────
function ScheduleSpeedProbesLive({
apiFetch,
serversForName,
}: {
apiFetch: ReturnType<typeof makeApiFetch>
serversForName: Server[]
}) {
const [rows, setRows] = useState<SpeedProbeApiRow[]>([])
const [loading, setLoading] = useState(true)
const [err, setErr] = useState<string | null>(null)
useEffect(() => {
let cancelled = false
setLoading(true)
setErr(null)
void apiFetch<{ probes: SpeedProbeApiRow[] }>("/api/uptime/speed-probes")
.then(d => {
if (!cancelled) setRows(d.probes ?? [])
})
.catch(e => {
if (!cancelled) setErr(e instanceof Error ? e.message : String(e))
})
.finally(() => {
if (!cancelled) setLoading(false)
})
return () => { cancelled = true }
}, [apiFetch])
const name = (id: string) => serversForName.find(s => s.id === id)?.name ?? id
if (loading) {
return (
<div className="flex items-center justify-center gap-2 py-12 text-sm text-muted-foreground">
<LoaderCircleIcon aria-hidden="true" className="size-5 motion-safe:animate-spin" />
Загрузка расписания из БД…
</div>
)
}
if (err) {
return (
<div className="flex items-center gap-2 rounded-lg border border-destructive/30 bg-destructive/10 px-4 py-3 text-sm text-destructive">
<AlertCircleIcon aria-hidden="true" className="size-4 shrink-0" />
{err}
</div>
)
}
return (
<div className="flex flex-col gap-3">
<DataPageCard>
<ProbesSpeedProbesDataGrid rows={rows} serverName={name} />
</DataPageCard>
<p className="text-[11px] text-muted-foreground">
Данные из коллектора uptime (та же БД, что и дашборд). Редактирование — через настройки мониторинга / API.
</p>
</div>
)
}
// ─── schedule tab ─────────────────────────────────────────────────────────────
const INIT_RULES: SchedRule[] = [
@@ -464,21 +402,12 @@ function ScheduleTab({
}) {
const [showAdd, setShowAdd] = useState(false)
const [addSrc, setAddSrc] = useState(defaultSrc ?? serverOptions[0]?.id ?? "srv1")
const [addTun, setAddTun] = useState("")
const [selectedTunnel, setAddTun] = useState("")
const [addType, setAddType] = useState<SchedType>("ping")
const [addMin, setAddMin] = useState(10)
const addTunnels = useMemo(() => tunnelsForServer(addSrc), [addSrc, tunnelsForServer])
useEffect(() => {
if (defaultSrc) setAddSrc(defaultSrc)
}, [defaultSrc])
useEffect(() => {
const list = tunnelsForServer(addSrc)
if (list.length && !list.some(t => t.id === addTun)) {
setAddTun(list[0]?.id ?? "")
}
}, [addSrc, addTun, tunnelsForServer])
const addTun = addTunnels.some(t=>t.id===selectedTunnel) ? selectedTunnel : addTunnels[0]?.id ?? ""
const tunnelName = (srcId: string, tunnelId: string) =>
tunnelsForServer(srcId).find((t) => t.id === tunnelId)?.name
@@ -504,7 +433,7 @@ function ScheduleTab({
</div>
<div className="px-4 py-4 flex flex-wrap items-end gap-3">
<div><OptionLabel>Сервер</OptionLabel>
<NativeSelect ariaLabel="Устройство расписания" value={addSrc} onChange={setAddSrc} className="min-w-[160px]">
<NativeSelect ariaLabel="Устройство расписания" value={addSrc} onChange={value=>{setAddSrc(value);setAddTun("")}} className="min-w-[160px]">
{serverOptions.filter(s => s.enabled).map(s => <option key={s.id} value={s.id}>{s.name}</option>)}
</NativeSelect>
</div>
@@ -1195,9 +1124,10 @@ function ProbesContent() {
{/* schedule */}
{tab === "schedule" && (
isLive
? <ScheduleSpeedProbesLive apiFetch={apiFetch} serversForName={allServers} />
? <ProbesSpeedSchedule base={backendUrl} serversForName={allServers} />
: (
<ScheduleTab
key={srcId}
rules={rules}
setRules={setRules}
serverOptions={allServers}