import { useParams, Link } from "react-router-dom"
import { Server, ExternalLink, Terminal } from "lucide-react"
import { useService, useStatus, useCaddyfile } from "@/services/api/hooks"
import { launcherLabel, subdomainUrl } from "@/lib/labels"
import { HealthBadge } from "@/components/HealthBadge"
import { LogViewer } from "@/components/LogViewer"
import { DetailHeader } from "@/components/detail/DetailHeader"
import { ServiceControls } from "@/components/detail/ServiceControls"
import { SystemdPanel } from "@/components/detail/SystemdPanel"
import { ConfigPanel } from "@/components/detail/ConfigPanel"
export function ServiceDetailPage() {
const { name } = useParams<{ name: string }>()
const { data: deployment, isLoading, error, refetch } = useService(name ?? "")
const { data: statusResp } = useStatus()
const health = statusResp?.statuses.find((s) => s.id === name)
const isGateway = name === "castle-gateway"
const { data: caddyfile } = useCaddyfile(isGateway)
if (isLoading) {
return (
Loading...
)
}
if (error || !deployment) {
return (
Service not found
)
}
// A static is a caddy-served site, not a systemd unit — no start/stop, no logs;
// it shows its served URL and the dir it serves instead of a port/launcher.
const isStatic = deployment.kind === "static" || deployment.manager === "caddy"
const servedUrl = subdomainUrl(deployment.subdomain ?? deployment.id)
const root = (deployment.manifest?.root as string | undefined) ?? undefined
return (
{!isStatic && (
{health && }
)}
Overview
{isStatic && (
<>
Status
● served by the gateway
· manager: caddy
{servedUrl && (
<>
Served at{deployment.subdomain ?? deployment.id}
>
)}
{root && (
<>
Root{root}
>
)}
>
)}
{deployment.port && (
<>
Port:{deployment.port}
>
)}
{deployment.health_path && (
<>
Health{deployment.health_path}
>
)}
{/* A static already shows its gateway URL as "Served at" above; only a
proxied (systemd) service surfaces the same thing as "Subdomain". */}
{!isStatic && deployment.subdomain && (
<>
Subdomain{deployment.subdomain}
>
)}
{deployment.launcher && (
<>
Launch
{launcherLabel(deployment.launcher)}
{deployment.run_target && <> · {deployment.run_target}>}
>
)}
{deployment.program && (
<>
Program
{deployment.program}
>
)}
{deployment.port && (
<>
Docs
OpenAPI docs
>
)}