Add delete action for recurring templates

There was no way to remove a template once created (e.g. test/scratch
recurring tasks) - only edit/pause via active. DELETE /api/templates/:id
detaches any tasks already spawned from it (template_id cleared) rather
than blocking on the FK or cascading, so existing task history survives
as ordinary one-off tasks while the recurring schedule itself is removed.
Delete button in the edit modal footer, only shown when editing an
existing template - not on new/duplicate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-08-26 11:58:52 +00:00
parent 690de73172
commit 763e7be6ca
3 changed files with 36 additions and 2 deletions

View file

@ -1,9 +1,9 @@
import { Fragment, useCallback, useEffect, useMemo, useState } from 'react'
import { Plus, X, Play, Copy, ChevronRight } from 'lucide-react'
import { Plus, X, Play, Copy, ChevronRight, Trash2 } from 'lucide-react'
import type { Template, TemplateGroup, Category, Location, Asset, Priority, ScheduleMode } from '../types'
import { PRIORITIES, PRIORITY_LABELS, can } from '../types'
import {
fetchTemplates, createTemplate, updateTemplate, runDueTemplates, fetchLocations, fetchAssets,
fetchTemplates, createTemplate, updateTemplate, deleteTemplate, runDueTemplates, fetchLocations, fetchAssets,
fetchTemplateGroups, upsertTemplateGroup,
} from '../api'
import { useAuth } from '../components/AuthGate'
@ -194,6 +194,18 @@ export default function Recurring() {
}
}
async function remove(id: number) {
if (!window.confirm('Delete this recurring template? Any tasks it already spawned stay in your history, but the schedule stops.')) return
try {
await deleteTemplate(id)
setForm(null)
setError(null)
load()
} catch (err) {
setError(err instanceof Error ? err.message : 'Delete failed')
}
}
function renderRow(t: Template) {
return (
<tr key={t.id} className={canManage ? 'clickable' : ''} onClick={() => openEdit(t)}>
@ -399,6 +411,14 @@ export default function Recurring() {
</label>
)}
{form.id && (
<div className="modal-footer-actions">
<button className="btn-ghost-sm btn-ghost-danger" onClick={() => remove(form.id!)} title="Delete this recurring template">
<Trash2 size={13} strokeWidth={1.75} /> Delete template
</button>
</div>
)}
<div className="modal-actions">
<button className="btn" onClick={() => setForm(null)}>Cancel</button>
<button className="btn btn-primary" onClick={save}>Save</button>