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.
This commit is contained in:
2026-07-01 11:32:25 -07:00
parent 8120ec9f9e
commit 6ee6d4c850
4 changed files with 108 additions and 85 deletions

View File

@@ -2,16 +2,29 @@ import { Link } from "react-router-dom"
import type { ProgramSummary } from "@/types"
import { KindBadge } from "./KindBadge"
import { StackBadge } from "./StackBadge"
import { ProgramActions } from "./ProgramActions"
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-start justify-between mb-2">
<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"
@@ -26,18 +39,8 @@ export function ProgramCard({ program }: ProgramCardProps) {
</div>
{program.description && (
<p className="text-sm text-[var(--muted)] mb-3">{program.description}</p>
<p className="text-sm text-[var(--muted)]">{program.description}</p>
)}
<div className="relative z-10">
<ProgramActions
name={program.id}
actions={program.actions}
active={program.active}
kind={program.kind}
compact
/>
</div>
</div>
)
}