fix(machines): ensure machine details probe resolves
This commit is contained in:
parent
3fce36d4e5
commit
55316e51c6
2 changed files with 68 additions and 33 deletions
|
|
@ -15,9 +15,11 @@ export async function GET(_req: NextRequest, ctx: { params: Promise<{ id: string
|
||||||
return NextResponse.json(data, { status: 200 })
|
return NextResponse.json(data, { status: 200 })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof ConvexConfigurationError) {
|
if (err instanceof ConvexConfigurationError) {
|
||||||
|
console.error("[api] admin/machines/[id]/details configuration error", err)
|
||||||
return NextResponse.json({ error: err.message }, { status: 500 })
|
return NextResponse.json({ error: err.message }, { status: 500 })
|
||||||
}
|
}
|
||||||
console.error("[api] admin/machines/[id]/details error", err)
|
console.error("[api] admin/machines/[id]/details error", err)
|
||||||
return NextResponse.json({ error: "Internal error" }, { status: 500 })
|
const message = err instanceof Error && err.message ? err.message : "Internal error"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { useEffect, useMemo, useRef, useState } from "react"
|
import { useEffect, useMemo, useState } from "react"
|
||||||
import { useQuery } from "convex/react"
|
import { useQuery } from "convex/react"
|
||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
import { api } from "@/convex/_generated/api"
|
import { api } from "@/convex/_generated/api"
|
||||||
|
|
@ -27,16 +27,14 @@ export function AdminMachineDetailsClient({ tenantId: _tenantId, machineId }: {
|
||||||
const [fallback, setFallback] = useState<Record<string, unknown> | null | undefined>(undefined)
|
const [fallback, setFallback] = useState<Record<string, unknown> | null | undefined>(undefined)
|
||||||
const [loadError, setLoadError] = useState<string | null>(null)
|
const [loadError, setLoadError] = useState<string | null>(null)
|
||||||
const [retryTick, setRetryTick] = useState(0)
|
const [retryTick, setRetryTick] = useState(0)
|
||||||
const timer = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
||||||
const shouldLoad = fallback === undefined && Boolean(machineId)
|
const shouldLoad = fallback === undefined && Boolean(machineId)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!shouldLoad) return
|
if (!shouldLoad) return
|
||||||
(async () => {
|
let cancelled = false
|
||||||
# immediate probe without delay
|
|
||||||
|
const probe = async () => {
|
||||||
try {
|
try {
|
||||||
// 1) Tenta via Convex direto do browser (independe do servidor)
|
|
||||||
const convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL
|
const convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL
|
||||||
if (convexUrl) {
|
if (convexUrl) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -45,54 +43,90 @@ export function AdminMachineDetailsClient({ tenantId: _tenantId, machineId }: {
|
||||||
id: machineId as Id<"machines">,
|
id: machineId as Id<"machines">,
|
||||||
includeMetadata: true,
|
includeMetadata: true,
|
||||||
})) as Record<string, unknown> | null
|
})) as Record<string, unknown> | null
|
||||||
|
|
||||||
|
if (cancelled) return
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
setFallback(data)
|
setFallback(data)
|
||||||
setLoadError(null)
|
setLoadError(null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} catch {
|
|
||||||
// continua para o plano B
|
if (data === null) {
|
||||||
|
setFallback(null)
|
||||||
|
setLoadError(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (cancelled) return
|
||||||
|
console.warn("[admin-machine-details] Convex probe failed, falling back to API route", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Plano B: rota do servidor (útil em ambientes sem Convex público)
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/admin/machines/${machineId}/details`, { credentials: "include" })
|
const res = await fetch(`/api/admin/machines/${machineId}/details`, {
|
||||||
|
credentials: "include",
|
||||||
|
cache: "no-store",
|
||||||
|
})
|
||||||
|
|
||||||
|
if (cancelled) return
|
||||||
|
|
||||||
|
let payload: Record<string, unknown> | null = null
|
||||||
|
try {
|
||||||
|
payload = (await res.json()) as Record<string, unknown> | null
|
||||||
|
} catch {
|
||||||
|
payload = null
|
||||||
|
}
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const data = (await res.json()) as Record<string, unknown>
|
setFallback(payload ?? null)
|
||||||
setFallback(data ?? null)
|
setLoadError(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const message =
|
||||||
|
typeof payload?.error === "string" && payload.error
|
||||||
|
? payload.error
|
||||||
|
: `Falha ao carregar (HTTP ${res.status})`
|
||||||
|
|
||||||
|
if (res.status === 404) {
|
||||||
|
setFallback(null)
|
||||||
setLoadError(null)
|
setLoadError(null)
|
||||||
} else {
|
} else {
|
||||||
let message = `Falha ao carregar (HTTP ${res.status})`
|
setLoadError(message)
|
||||||
try {
|
}
|
||||||
const payload = (await res.json()) as Record<string, unknown>
|
} catch (err) {
|
||||||
if (typeof payload?.error === "string" && payload.error) {
|
if (!cancelled) {
|
||||||
message = payload.error
|
console.error("[admin-machine-details] API fallback fetch failed", err)
|
||||||
}
|
setLoadError("Erro de rede ao carregar os dados da máquina.")
|
||||||
} catch {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
if (res.status == 404) {
|
|
||||||
setFallback(null)
|
|
||||||
} else {
|
|
||||||
setLoadError(message)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch {
|
|
||||||
setLoadError("Erro de rede ao carregar os dados da máquina.")
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (!cancelled) {
|
||||||
|
console.error("[admin-machine-details] Unexpected probe failure", err)
|
||||||
|
setLoadError("Erro de rede ao carregar os dados da máquina.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
probe().catch((err) => {
|
||||||
|
if (!cancelled) {
|
||||||
|
console.error("[admin-machine-details] Probe promise rejected", err)
|
||||||
setLoadError("Erro de rede ao carregar os dados da máquina.")
|
setLoadError("Erro de rede ao carregar os dados da máquina.")
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true
|
||||||
|
}
|
||||||
}, [shouldLoad, machineId, retryTick])
|
}, [shouldLoad, machineId, retryTick])
|
||||||
|
|
||||||
// Timeout de proteção: se depois de X segundos ainda estiver carregando e sem fallback, mostra erro claro
|
// Timeout de proteção: se depois de X segundos ainda estiver carregando e sem fallback, mostra erro claro
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!shouldLoad) return
|
if (!shouldLoad) return
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
setLoadError(
|
setLoadError((error) =>
|
||||||
"Tempo esgotado ao consultar os dados (Convex). Verifique sua conexão e tente novamente."
|
error ?? "Tempo esgotado ao consultar os dados (Convex). Verifique sua conexão e tente novamente."
|
||||||
)
|
)
|
||||||
}, 10_000)
|
}, 10_000)
|
||||||
return () => clearTimeout(timeout)
|
return () => clearTimeout(timeout)
|
||||||
|
|
@ -108,7 +142,7 @@ export function AdminMachineDetailsClient({ tenantId: _tenantId, machineId }: {
|
||||||
|
|
||||||
const onRetry = () => {
|
const onRetry = () => {
|
||||||
setLoadError(null)
|
setLoadError(null)
|
||||||
setFallback(null)
|
setFallback(undefined)
|
||||||
setRetryTick((t) => t + 1)
|
setRetryTick((t) => t + 1)
|
||||||
// força revalidação de RSC/convex subscription
|
// força revalidação de RSC/convex subscription
|
||||||
try {
|
try {
|
||||||
|
|
@ -159,4 +193,3 @@ export function AdminMachineDetailsClient({ tenantId: _tenantId, machineId }: {
|
||||||
|
|
||||||
return <MachineDetails machine={machine} />
|
return <MachineDetails machine={machine} />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue