refactor: replace custom API fetch logic with requestJson utility across multiple pages
Updated the API fetching mechanism in various components to utilize the new requestJson function for improved consistency and error handling. This change affects the alerts, dashboard, data collection, filters, gre, network map, probes, recursive routes, route optimizer, servers, settings, traffic, and uptime pages.
This commit is contained in:
+35
-96
@@ -5,71 +5,21 @@ import { PageHeader } from "@/components/page-header"
|
||||
import { StatusBadge } from "@/components/status-badge"
|
||||
import { servers as initialServers } from "@/lib/data"
|
||||
import type { ServerType, Server, WanUplink } from "@/lib/data"
|
||||
import type { ServerCreate, ServerUpdate } from "@/packages/contracts/src/servers"
|
||||
import { toFrontendServer } from "@/entities/server/model/mappers"
|
||||
import {
|
||||
createServer,
|
||||
deleteServer,
|
||||
getServer,
|
||||
listServers,
|
||||
pollServer,
|
||||
testServerConnection,
|
||||
updateServer,
|
||||
} from "@/shared/api/servers"
|
||||
|
||||
// ─── Backend integration ──────────────────────────────────────────────────────
|
||||
|
||||
import { useDataSource } from "@/lib/data-source"
|
||||
|
||||
interface BackendServer {
|
||||
id: number; name: string; host: string; port: number
|
||||
useSsl: boolean; verifySsl: boolean; username: string; password: string
|
||||
type: ServerType; site: string; country: string; asn: string
|
||||
comment: string; enabled: boolean
|
||||
lanSubnet: string
|
||||
wanUplinks: WanUplink[]
|
||||
status: "online" | "offline" | null; latency: number | null
|
||||
os: string | null; model: string | null; uptime: string | null
|
||||
cpuLoad: number | null; freeMemory: number | null; totalMemory: number | null
|
||||
identityName: string | null
|
||||
sessions: number; polledAt: string | null
|
||||
createdAt: string; updatedAt: string
|
||||
}
|
||||
|
||||
function toFrontend(s: BackendServer): Server {
|
||||
return {
|
||||
id: String(s.id),
|
||||
name: s.name || s.host,
|
||||
host: s.host,
|
||||
type: s.type,
|
||||
site: s.site,
|
||||
country: s.country,
|
||||
asn: s.asn,
|
||||
model: s.model ?? "—",
|
||||
os: s.os ?? "—",
|
||||
enabled: s.enabled,
|
||||
status: s.status ?? "offline",
|
||||
latency: s.latency != null ? Math.round(s.latency) : null,
|
||||
sessions: s.sessions ?? 0,
|
||||
comment: s.comment || undefined,
|
||||
lanSubnet: s.lanSubnet || undefined,
|
||||
wanUplinks: Array.isArray(s.wanUplinks) && s.wanUplinks.length ? s.wanUplinks : undefined,
|
||||
// carry extra fields needed for expanded view
|
||||
uptime: s.uptime ?? undefined,
|
||||
cpuLoad: s.cpuLoad ?? undefined,
|
||||
freeMemory: s.freeMemory ?? undefined,
|
||||
totalMemory: s.totalMemory ?? undefined,
|
||||
polledAt: s.polledAt ?? undefined,
|
||||
}
|
||||
}
|
||||
|
||||
function makeApiFetch(backendUrl: string) {
|
||||
return async function apiFetch<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
const headers: HeadersInit = init?.body
|
||||
? { "Content-Type": "application/json" }
|
||||
: {}
|
||||
const res = await fetch(backendUrl.replace(/\/$/, "") + path, {
|
||||
...init,
|
||||
headers: { ...headers, ...(init?.headers ?? {}) },
|
||||
})
|
||||
if (!res.ok) {
|
||||
const err = await res.json().catch(() => ({ error: res.statusText })) as { error?: string }
|
||||
throw new Error(err.error ?? res.statusText)
|
||||
}
|
||||
// 204 No Content
|
||||
if (res.status === 204) return undefined as T
|
||||
return res.json() as Promise<T>
|
||||
}
|
||||
}
|
||||
import { Flag } from "@/components/flag"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
@@ -373,7 +323,6 @@ type SheetMode = "add" | "edit"
|
||||
export default function ServersPage() {
|
||||
const { mode, backendUrl, backendStatus } = useDataSource()
|
||||
const isLive = mode === "live" && backendStatus === true
|
||||
const apiFetch = makeApiFetch(backendUrl)
|
||||
|
||||
const [serverList, setServerList] = useState<Server[]>(initialServers)
|
||||
const [_backendOk, setBackendOk] = useState(false)
|
||||
@@ -402,10 +351,10 @@ export default function ServersPage() {
|
||||
})
|
||||
return
|
||||
}
|
||||
apiFetch<BackendServer[]>("/api/servers")
|
||||
listServers(backendUrl)
|
||||
.then(data => {
|
||||
setBackendOk(true)
|
||||
setServerList(data.map(toFrontend))
|
||||
setServerList(data.map(toFrontendServer))
|
||||
})
|
||||
.catch(() => {
|
||||
setBackendOk(false)
|
||||
@@ -437,7 +386,7 @@ export default function ServersPage() {
|
||||
// Fetch full server details (including credentials) from backend
|
||||
if (isLive) {
|
||||
try {
|
||||
const full = await apiFetch<BackendServer>(`/api/servers/${s.id}`)
|
||||
const full = await getServer(backendUrl, s.id)
|
||||
setForm(prev => ({
|
||||
...prev,
|
||||
username: full.username ?? "",
|
||||
@@ -458,7 +407,7 @@ export default function ServersPage() {
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
const payload = {
|
||||
const payload: ServerCreate = {
|
||||
host: form.host,
|
||||
port: Number(form.port) || (form.proto === "https" ? 443 : 80),
|
||||
username: form.username,
|
||||
@@ -479,17 +428,12 @@ export default function ServersPage() {
|
||||
if (isLive) {
|
||||
try {
|
||||
if (sheetMode === "edit" && editingId) {
|
||||
const updated = await apiFetch<BackendServer>(
|
||||
`/api/servers/${editingId}`,
|
||||
{ method: "PUT", body: JSON.stringify(payload) },
|
||||
)
|
||||
setServerList(list => list.map(s => s.id === editingId ? toFrontend(updated) : s))
|
||||
const updatedPayload: ServerUpdate = payload
|
||||
const updated = await updateServer(backendUrl, editingId, updatedPayload)
|
||||
setServerList(list => list.map(s => s.id === editingId ? toFrontendServer(updated) : s))
|
||||
} else {
|
||||
const created = await apiFetch<BackendServer>(
|
||||
"/api/servers",
|
||||
{ method: "POST", body: JSON.stringify(payload) },
|
||||
)
|
||||
setServerList(list => [...list, toFrontend(created)])
|
||||
const created = await createServer(backendUrl, payload)
|
||||
setServerList(list => [...list, toFrontendServer(created)])
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Ошибка сохранения:", e)
|
||||
@@ -540,7 +484,7 @@ export default function ServersPage() {
|
||||
async function handleDelete(id: string) {
|
||||
if (isLive) {
|
||||
try {
|
||||
await apiFetch(`/api/servers/${id}`, { method: "DELETE" })
|
||||
await deleteServer(backendUrl, id)
|
||||
} catch (e) {
|
||||
console.error("Ошибка удаления:", e)
|
||||
}
|
||||
@@ -552,10 +496,10 @@ export default function ServersPage() {
|
||||
if (!isLive) return
|
||||
setPollingIds(p => new Set(p).add(id))
|
||||
try {
|
||||
await apiFetch(`/api/servers/${id}/poll`, { method: "POST" })
|
||||
await pollServer(backendUrl, id)
|
||||
// Reload full list to get updated status/version
|
||||
const data = await apiFetch<BackendServer[]>("/api/servers")
|
||||
setServerList(data.map(toFrontend))
|
||||
const data = await listServers(backendUrl)
|
||||
setServerList(data.map(toFrontendServer))
|
||||
} catch (e) {
|
||||
console.error("Poll error:", e)
|
||||
} finally {
|
||||
@@ -568,9 +512,9 @@ export default function ServersPage() {
|
||||
setPollAllBusy(true)
|
||||
try {
|
||||
const ids = serverList.map(s => s.id)
|
||||
await Promise.all(ids.map(id => apiFetch(`/api/servers/${id}/poll`, { method: "POST" }).catch(() => {})))
|
||||
const data = await apiFetch<BackendServer[]>("/api/servers")
|
||||
setServerList(data.map(toFrontend))
|
||||
await Promise.all(ids.map(id => pollServer(backendUrl, id).catch(() => {})))
|
||||
const data = await listServers(backendUrl)
|
||||
setServerList(data.map(toFrontendServer))
|
||||
} finally {
|
||||
setPollAllBusy(false)
|
||||
}
|
||||
@@ -582,20 +526,15 @@ export default function ServersPage() {
|
||||
}
|
||||
setTestState("testing"); setTestMsg("")
|
||||
try {
|
||||
const res = await fetch(backendUrl.replace(/\/$/, "") + "/api/servers/test-connection", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
host: form.host,
|
||||
port: Number(form.port) || (form.proto === "https" ? 443 : 80),
|
||||
useSsl: form.proto === "https",
|
||||
verifySsl: form.verifySsl,
|
||||
apiPath: form.apiPath || "/rest",
|
||||
username: form.username,
|
||||
password: form.password,
|
||||
}),
|
||||
const data = await testServerConnection(backendUrl, {
|
||||
host: form.host,
|
||||
port: Number(form.port) || (form.proto === "https" ? 443 : 80),
|
||||
useSsl: form.proto === "https",
|
||||
verifySsl: form.verifySsl,
|
||||
apiPath: form.apiPath || "/rest",
|
||||
username: form.username,
|
||||
password: form.password,
|
||||
})
|
||||
const data = await res.json() as { success: boolean; message: string }
|
||||
if (data.success) {
|
||||
setTestState("ok"); setTestMsg(data.message)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user