fix: Sprint-Zuordnung im Eingang sichtbarer machen.
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Test Suite / pytest-backend (push) Successful in 2m52s
Test Suite / lint-backend (push) Successful in 3s
Test Suite / compose-smoke (push) Has been skipped
Test Suite / k6 /api/health Baseline (push) Successful in 18s
Test Suite / playwright-smoke (push) Successful in 13s

Ziel-Sprint-Dropdown immer wenn Sprint existiert, Setup-Hinweis ohne Sprint, Planen fuer alle commit-faehigen Backlog-Status.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Lars 2026-07-12 19:30:36 +02:00
parent 00567bb097
commit c19b6296ed
2 changed files with 43 additions and 20 deletions

View File

@ -10,6 +10,8 @@ import { computeDropPatches, computeMovePatches, sortByOrder } from '../utils/re
import { useMinWidth } from '../hooks/useMinWidth.js'
const PLANNING_STATUSES = new Set(['planned', 'active', 'at_risk'])
/** Backend erlaubt Convert für diese Status — UI war nur bei „Freigegeben“ sichtbar. */
const COMMITTABLE_STATUSES = new Set(['accepted', 'triaged', 'new'])
export function BacklogSection({
items,
@ -137,8 +139,8 @@ export function BacklogSection({
const modalTitle =
modalMode?.kind === 'create' ? 'Backlog-Item anlegen' : 'Backlog-Item bearbeiten'
const acceptedItems = sortedItems.filter((item) => item.status === 'accepted')
const selectedAccepted = acceptedItems.filter((item) => selectedIds.has(item.id))
const committableItems = sortedItems.filter((item) => COMMITTABLE_STATUSES.has(item.status))
const selectedCommittable = committableItems.filter((item) => selectedIds.has(item.id))
function toggleSelected(itemId) {
setSelectedIds((prev) => {
@ -163,14 +165,14 @@ export function BacklogSection({
}
async function handleBulkPlan() {
if (!selectedAccepted.length) return
if (!selectedCommittable.length) return
if (typeof onBulkConvert === 'function') {
await onBulkConvert(
selectedAccepted.map((item) => item.id),
selectedCommittable.map((item) => item.id),
convertOptions(),
)
} else {
for (const item of selectedAccepted) {
for (const item of selectedCommittable) {
await onConvert(item.id, convertOptions())
}
}
@ -195,10 +197,22 @@ export function BacklogSection({
)}
</div>
{showSprintPlanning && canManage && acceptedItems.length > 0 && (
{sprintPlanningEnabled && canManage && !showSprintPlanning && (
<div className="backlog-sprint-setup card-list-item">
<p className="backlog-sprint-setup__title">
<strong>Sprint-Planung:</strong> Lege zuerst einen Sprint an.
</p>
<p className="muted backlog-sprint-planning__hint">
Plan Sprint Sprint anlegen (optional Sofort aktivieren). Danach erscheint hier
die Sprint-Auswahl zum Committen aus dem Eingang.
</p>
</div>
)}
{showSprintPlanning && canManage && (
<div className="backlog-sprint-planning card-list-item">
<label className="backlog-sprint-planning__field">
<span className="muted">Sprint-Ziel</span>
<span className="muted">Ziel-Sprint</span>
<select
value={sprintTargetId}
onChange={(e) => setSprintTargetId(e.target.value)}
@ -207,33 +221,30 @@ export function BacklogSection({
{planableSprints.map((cycle) => (
<option key={cycle.id} value={cycle.id}>
{cycle.title}
{cycle.status === 'active' ? ' (aktiv)' : ''}
{cycle.status === 'active' ? ' (aktiv)' : cycle.status === 'planned' ? ' (geplant)' : ''}
</option>
))}
</select>
</label>
{selectedAccepted.length > 0 && (
{selectedCommittable.length > 0 && (
<button
type="button"
className="btn btn-primary btn-sm"
disabled={busy || !sprintTargetId}
onClick={handleBulkPlan}
>
{selectedAccepted.length} Item{selectedAccepted.length === 1 ? '' : 's'} {convertLabel}
{selectedCommittable.length} Item{selectedCommittable.length === 1 ? '' : 's'}{' '}
{convertLabel}
</button>
)}
<p className="muted backlog-sprint-planning__hint">
Items markieren und in den gewählten Sprint committen Planung unter Plan Sprint.
{committableItems.length === 0
? 'Lege Backlog-Items an — dann per Checkbox markieren und in den Sprint committen.'
: 'Checkbox am Item → „In Sprint planen“. Committen erzeugt ein Arbeitspaket mit Sprint-Zuweisung.'}
</p>
</div>
)}
{sprintPlanningEnabled && canManage && acceptedItems.length > 0 && planableSprints.length === 0 && (
<p className="muted backlog-sprint-planning__hint">
Lege zuerst einen Sprint unter Plan Sprint an, um Backlog-Items zu planen.
</p>
)}
{items.length === 0 && <EmptyState message="Backlog ist leer." />}
<ul className="item-list backlog-reorder-list">
@ -262,7 +273,7 @@ export function BacklogSection({
</span>
)}
{showSprintPlanning && canManage && item.status === 'accepted' && (
{showSprintPlanning && canManage && COMMITTABLE_STATUSES.has(item.status) && (
<label className="backlog-select-checkbox">
<input
type="checkbox"
@ -304,14 +315,14 @@ export function BacklogSection({
<PriorityBadge priority={item.priority} />
{canManage && item.status !== 'converted' && (
<>
{item.status === 'accepted' && (
{COMMITTABLE_STATUSES.has(item.status) && (
<button
type="button"
className="btn btn-primary btn-sm"
onClick={() => handleSingleConvert(item.id)}
disabled={busy || (showSprintPlanning && !sprintTargetId)}
>
{convertLabel}
{showSprintPlanning ? convertLabel : 'In Arbeitspaket umwandeln'}
</button>
)}
<button

View File

@ -670,6 +670,18 @@
background: var(--jk-surface);
}
.backlog-sprint-setup {
margin-bottom: 16px;
padding: 12px;
border-left: 3px solid var(--jk-primary);
background: var(--jk-surface-muted, rgba(0, 0, 0, 0.03));
border-radius: 6px;
}
.backlog-sprint-setup__title {
margin: 0 0 6px;
}
.backlog-sprint-planning {
display: flex;
flex-wrap: wrap;