diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-07-18 00:14:45 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-07-18 00:14:45 +0000 |
| commit | f08f06bef47aac2c9effb4cec650d99c2deb2dd7 (patch) | |
| tree | ae06bd2e140c678e67f2879f21b07a4114a41f73 /web/templates/partials/chain-detail.html | |
| parent | be4d606e9a1f5b068abcc21bbac58d1e4705ea1f (diff) | |
Rework Tasks tab: Chains section, checklist modal, project visibility
The flat Tasks-tab atom list was silently dumping every chain step
(locked and unlocked) and dormant bucket-pool items in as ordinary
undated cards, with no chain/project context and no protection against
completing a locked step out of order.
- CompleteNativeTask now rejects completing a locked chain task
(ErrChainTaskLocked), mapped to 400 in both the widget and web
complete-atom handlers.
- Chain tasks and dormant bucket items are excluded from the flat atom
list; a new "Chains" section shows one card per active/paused chain
with the current step and N/M progress.
- New chain checklist modal (GET /chains/{id}) lists every position in
order with pause/resume/abandon -- the web view originally deferred
as Android-only.
- Fixed a real bug this surfaced: resuming a paused chain only flipped
the status flag, never unlocking the deferred successor, so a chain
paused right after a completion stayed stuck forever. SetChainStatus
now catches up the deferred advancement on resume, idempotently.
- Atom cards gained a project-name chip for general visibility.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
Diffstat (limited to 'web/templates/partials/chain-detail.html')
| -rw-r--r-- | web/templates/partials/chain-detail.html | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/web/templates/partials/chain-detail.html b/web/templates/partials/chain-detail.html new file mode 100644 index 0000000..3372f03 --- /dev/null +++ b/web/templates/partials/chain-detail.html @@ -0,0 +1,52 @@ +{{define "chain-detail"}} +<div class="p-4 space-y-4"> + <div class="flex items-center justify-between gap-2"> + <div> + <h3 class="text-white font-medium">{{.ProjectName}}</h3> + <p class="text-xs text-white/50 mt-0.5"> + {{.Chain.Status}} + {{range $i, $t := .Tasks}}{{if $t.ChainUnlocked}} · step {{add $i 1}} of {{len $.Tasks}}{{end}}{{end}} + </p> + </div> + <div class="flex gap-2 flex-shrink-0"> + {{if eq .Chain.Status "active"}} + <button hx-post="/chains/{{.Chain.ID}}/pause" + hx-on::after-request="if(event.detail.successful) { htmx.trigger(document.body, 'refresh-tasks'); closeChainModal(); }" + class="text-xs px-2 py-1 rounded bg-white/10 hover:bg-white/20 text-white/70">Pause</button> + {{else if eq .Chain.Status "paused"}} + <button hx-post="/chains/{{.Chain.ID}}/resume" + hx-on::after-request="if(event.detail.successful) { htmx.trigger(document.body, 'refresh-tasks'); closeChainModal(); }" + class="text-xs px-2 py-1 rounded bg-white/10 hover:bg-white/20 text-white/70">Resume</button> + {{end}} + <button hx-post="/chains/{{.Chain.ID}}/abandon" + hx-confirm="Abandon this chain? This can't be undone." + hx-on::after-request="if(event.detail.successful) { htmx.trigger(document.body, 'refresh-tasks'); closeChainModal(); }" + class="text-xs px-2 py-1 rounded bg-red-500/10 hover:bg-red-500/20 text-red-300/80">Abandon</button> + </div> + </div> + + <div class="space-y-1"> + {{range $i, $t := .Tasks}} + <div class="flex items-start gap-2 py-2 px-2 rounded-lg {{if $t.Completed}}opacity-50{{else if not $t.ChainUnlocked}}opacity-40{{end}}"> + {{if $t.Completed}} + <span class="mt-0.5 text-green-400 flex-shrink-0">✓</span> + {{else if $t.ChainUnlocked}} + <input type="checkbox" + hx-post="/complete-atom" + hx-vals='{"id": "{{$t.ID}}", "source": "doot"}' + hx-on::after-request="if(event.detail.successful) { htmx.trigger(document.body, 'refresh-tasks'); htmx.ajax('GET', '/chains/{{$.Chain.ID}}', {target:'#chain-view-content', swap:'innerHTML'}); }" + class="mt-0.5 h-4 w-4 rounded bg-black/40 border-white/30 text-white/80 focus:ring-white/30 cursor-pointer flex-shrink-0"> + {{else}} + <span class="mt-0.5 text-white/30 flex-shrink-0">🔒</span> + {{end}} + <div class="flex-1 min-w-0"> + <span class="text-sm {{if $t.Completed}}line-through text-white/50{{else if $t.ChainUnlocked}}text-white{{else}}text-white/40{{end}}">{{add $i 1}}. {{$t.Content}}</span> + {{if $t.Description}} + <p class="text-xs text-white/40 mt-0.5">{{$t.Description}}</p> + {{end}} + </div> + </div> + {{end}} + </div> +</div> +{{end}} |
