import { useState } from "react" import { useParams } from "react-router-dom" import { useProgram, useEventStream } from "@/services/api/hooks" import { runnerLabel } from "@/lib/labels" import { DetailHeader } from "@/components/detail/DetailHeader" import { ConfigPanel } from "@/components/detail/ConfigPanel" import { ProgramActions, ActionOutputPanel, type ActionOutput } from "@/components/ProgramActions" export function ProgramDetailPage() { useEventStream() const { name } = useParams<{ name: string }>() const { data: component, isLoading, error, refetch } = useProgram(name ?? "") const [actionOutput, setActionOutput] = useState(null) if (isLoading) { return (
Loading...
) } if (error || !component) { return (

Program not found

) } return (
{actionOutput && actionOutput.action && (
setActionOutput(null)} />
)} {component.description && (

{component.description}

)}

Program Info

Where the source lives and how castle works with it.

{component.source && ( <> Source {component.source} )} {component.repo && ( <> Repo {component.repo} {component.ref ? ` @ ${component.ref}` : ""} )} {component.version && ( <> Version {component.version} )} {component.runner && ( <> Runner {runnerLabel(component.runner)} )} {component.installed !== null && ( <> Installed {component.installed ? "Yes" : "No"} )}
{component.commands && Object.keys(component.commands).length > 0 && (
Commands
{Object.entries(component.commands).map(([verb, cmds]) => (
{verb} {cmds.map((argv) => argv.join(" ")).join(" && ")}
))}
)} {component.system_dependencies.length > 0 && (
System Dependencies
{component.system_dependencies.map((dep) => ( {dep} ))}
)}
) }