diff --git a/app/src/components/detail/JobFields.tsx b/app/src/components/detail/JobFields.tsx index df17aae..07f2176 100644 --- a/app/src/components/detail/JobFields.tsx +++ b/app/src/components/detail/JobFields.tsx @@ -74,6 +74,7 @@ export function JobFields({ job, onSave, onDelete }: Props) { onSave={handleSave} onDelete={onDelete ? () => onDelete(job.id) : undefined} deleteLabel="Remove job" + confirmMessage={`Remove job "${job.id}" from castle.yaml? Run a deploy afterward to tear down its timer.`} /> ) diff --git a/app/src/components/detail/ProgramFields.tsx b/app/src/components/detail/ProgramFields.tsx index 8e2d3bb..f4eb8ff 100644 --- a/app/src/components/detail/ProgramFields.tsx +++ b/app/src/components/detail/ProgramFields.tsx @@ -95,6 +95,12 @@ export function ProgramFields({ program, onSave, onDelete }: Props) { onSave={handleSave} onDelete={onDelete ? () => onDelete(program.id) : undefined} deleteLabel="Remove program" + confirmMessage={`Remove program "${program.id}" from castle.yaml? (Source on disk is untouched.)`} + deleteBlocked={ + program.services.length + program.jobs.length > 0 + ? "Programs with active jobs or services cannot be removed — delete those first." + : undefined + } /> ) diff --git a/app/src/components/detail/ServiceFields.tsx b/app/src/components/detail/ServiceFields.tsx index aa54b51..9185286 100644 --- a/app/src/components/detail/ServiceFields.tsx +++ b/app/src/components/detail/ServiceFields.tsx @@ -119,6 +119,7 @@ export function ServiceFields({ service, onSave, onDelete }: Props) { onSave={handleSave} onDelete={onDelete ? () => onDelete(service.id) : undefined} deleteLabel="Remove service" + confirmMessage={`Remove service "${service.id}" from castle.yaml? Run a deploy afterward to tear down its unit.`} /> ) diff --git a/app/src/components/detail/fields.tsx b/app/src/components/detail/fields.tsx index ee0ceb6..672a334 100644 --- a/app/src/components/detail/fields.tsx +++ b/app/src/components/detail/fields.tsx @@ -122,18 +122,27 @@ export function FormFooter({ onSave, onDelete, deleteLabel, + confirmMessage, + deleteBlocked, }: { saving: boolean saved: boolean onSave: () => void onDelete?: () => void deleteLabel: string + confirmMessage?: string + /** When set, removal is disallowed and this reason is shown instead of the button. */ + deleteBlocked?: string }) { return (
- {onDelete ? ( + {deleteBlocked ? ( + {deleteBlocked} + ) : onDelete ? (