Files
wild-pc/app/src/components/ProgramCard.tsx
Paul Payne 6ee6d4c850 Dashboard: lifecycle is a deployment concern, not a program action
Install/Uninstall no longer live in the program's action cluster (they were a
tool's PATH-deployment lifecycle masquerading as a program action). ProgramActions
is now dev-verbs-only (build/test/lint/type-check/check). The program detail's
Deployment section owns lifecycle, keyed on kind: a tool shows Installed-on-PATH
with an Install/Uninstall toggle, a static shows served-by-gateway + its URL,
services/jobs link to their own pages. Program list cards drop the quick toggle
for a plain active dot. 'Remove program' stays as catalog deletion — no longer a
dead-end now that the blocking deployment is visible in the Deployment section.
2026-07-01 11:32:25 -07:00

47 lines
1.6 KiB
TypeScript

import { Link } from "react-router-dom"
import type { ProgramSummary } from "@/types"
import { KindBadge } from "./KindBadge"
import { StackBadge } from "./StackBadge"
interface ProgramCardProps {
program: ProgramSummary
}
export function ProgramCard({ program }: ProgramCardProps) {
// The dot reflects the uniform lifecycle state (a tool on PATH, a service
// running, a static site served). Lifecycle controls live on the detail page's
// Deployment section, not here — a card just shows state and links through.
const dot =
program.active === true
? "bg-green-500"
: program.active === false
? "bg-[var(--muted)]"
: "bg-transparent border border-[var(--muted)]"
return (
<div className="relative bg-[var(--card)] border border-[var(--border)] rounded-lg p-5 hover:border-[var(--primary)] transition-colors">
<div className="flex items-center gap-2 mb-2">
<span
className={`h-2 w-2 rounded-full shrink-0 ${dot}`}
title={program.active === true ? "active" : program.active === false ? "inactive" : "no deployment"}
/>
<Link
to={`/programs/${program.id}`}
className="text-base font-semibold hover:text-[var(--primary)] transition-colors after:absolute after:inset-0"
>
{program.id}
</Link>
</div>
<div className="flex flex-wrap gap-1.5 mb-2">
<KindBadge kind={program.kind} />
<StackBadge stack={program.stack} />
</div>
{program.description && (
<p className="text-sm text-[var(--muted)]">{program.description}</p>
)}
</div>
)
}