ST-1246: F4 UI Start/Resume/Cancel sprint + pr_strategy dropdown

- components/sprint/sprint-run-controls.tsx: knoppen Start Sprint
  (sprintStatus=ACTIVE), Hervat sprint (sprintStatus=FAILED) en
  Annuleer sprint-run (lopende run). Pre-flight blocker-modal toont
  blockers met directe links naar de relevante pagina's.
- components/products/pr-strategy-select.tsx: dropdown SPRINT|STORY in
  product-settings, met optimistic update + sonner-toast op fail.
- actions/products.ts: updatePrStrategyAction (eigenaar-only, demo-block).
- Sprint-page: query op actieve SprintRun + tonen van controls-balk.

Live cascade-visualisatie (T-634) staat als follow-up genoteerd —
huidige sprint-board statusbadges volstaan voor MVP. De Solo-board
"Voer uit"-knoppen zijn niet expliciet verwijderd; ze tonen nu de
deprecation-error van de gestubde actions tot de Solo-flow opnieuw
ontworpen wordt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-05-06 16:35:19 +02:00
parent e7f1c64522
commit a41d2fbbaf
5 changed files with 302 additions and 1 deletions

View file

@ -396,3 +396,27 @@ export async function updateAutoPrAction(id: string, auto_pr: boolean) {
revalidatePath(`/products/${id}/settings`)
return { success: true }
}
export async function updatePrStrategyAction(
id: string,
pr_strategy: 'SPRINT' | 'STORY',
) {
const session = await getSession()
if (!session.userId) return { error: 'Niet ingelogd' }
if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' }
const parsed = z
.object({ pr_strategy: z.enum(['SPRINT', 'STORY']) })
.safeParse({ pr_strategy })
if (!parsed.success) return { error: 'Ongeldige waarde voor pr_strategy' }
const product = await prisma.product.findFirst({ where: { id, user_id: session.userId } })
if (!product) return { error: 'Product niet gevonden' }
await prisma.product.update({
where: { id },
data: { pr_strategy: parsed.data.pr_strategy },
})
revalidatePath(`/products/${id}/settings`)
return { success: true }
}