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
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:
parent
00567bb097
commit
c19b6296ed
|
|
@ -10,6 +10,8 @@ import { computeDropPatches, computeMovePatches, sortByOrder } from '../utils/re
|
||||||
import { useMinWidth } from '../hooks/useMinWidth.js'
|
import { useMinWidth } from '../hooks/useMinWidth.js'
|
||||||
|
|
||||||
const PLANNING_STATUSES = new Set(['planned', 'active', 'at_risk'])
|
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({
|
export function BacklogSection({
|
||||||
items,
|
items,
|
||||||
|
|
@ -137,8 +139,8 @@ export function BacklogSection({
|
||||||
const modalTitle =
|
const modalTitle =
|
||||||
modalMode?.kind === 'create' ? 'Backlog-Item anlegen' : 'Backlog-Item bearbeiten'
|
modalMode?.kind === 'create' ? 'Backlog-Item anlegen' : 'Backlog-Item bearbeiten'
|
||||||
|
|
||||||
const acceptedItems = sortedItems.filter((item) => item.status === 'accepted')
|
const committableItems = sortedItems.filter((item) => COMMITTABLE_STATUSES.has(item.status))
|
||||||
const selectedAccepted = acceptedItems.filter((item) => selectedIds.has(item.id))
|
const selectedCommittable = committableItems.filter((item) => selectedIds.has(item.id))
|
||||||
|
|
||||||
function toggleSelected(itemId) {
|
function toggleSelected(itemId) {
|
||||||
setSelectedIds((prev) => {
|
setSelectedIds((prev) => {
|
||||||
|
|
@ -163,14 +165,14 @@ export function BacklogSection({
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleBulkPlan() {
|
async function handleBulkPlan() {
|
||||||
if (!selectedAccepted.length) return
|
if (!selectedCommittable.length) return
|
||||||
if (typeof onBulkConvert === 'function') {
|
if (typeof onBulkConvert === 'function') {
|
||||||
await onBulkConvert(
|
await onBulkConvert(
|
||||||
selectedAccepted.map((item) => item.id),
|
selectedCommittable.map((item) => item.id),
|
||||||
convertOptions(),
|
convertOptions(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
for (const item of selectedAccepted) {
|
for (const item of selectedCommittable) {
|
||||||
await onConvert(item.id, convertOptions())
|
await onConvert(item.id, convertOptions())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -195,10 +197,22 @@ export function BacklogSection({
|
||||||
)}
|
)}
|
||||||
</div>
|
</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">
|
<div className="backlog-sprint-planning card-list-item">
|
||||||
<label className="backlog-sprint-planning__field">
|
<label className="backlog-sprint-planning__field">
|
||||||
<span className="muted">Sprint-Ziel</span>
|
<span className="muted">Ziel-Sprint</span>
|
||||||
<select
|
<select
|
||||||
value={sprintTargetId}
|
value={sprintTargetId}
|
||||||
onChange={(e) => setSprintTargetId(e.target.value)}
|
onChange={(e) => setSprintTargetId(e.target.value)}
|
||||||
|
|
@ -207,33 +221,30 @@ export function BacklogSection({
|
||||||
{planableSprints.map((cycle) => (
|
{planableSprints.map((cycle) => (
|
||||||
<option key={cycle.id} value={cycle.id}>
|
<option key={cycle.id} value={cycle.id}>
|
||||||
{cycle.title}
|
{cycle.title}
|
||||||
{cycle.status === 'active' ? ' (aktiv)' : ''}
|
{cycle.status === 'active' ? ' (aktiv)' : cycle.status === 'planned' ? ' (geplant)' : ''}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
{selectedAccepted.length > 0 && (
|
{selectedCommittable.length > 0 && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-primary btn-sm"
|
className="btn btn-primary btn-sm"
|
||||||
disabled={busy || !sprintTargetId}
|
disabled={busy || !sprintTargetId}
|
||||||
onClick={handleBulkPlan}
|
onClick={handleBulkPlan}
|
||||||
>
|
>
|
||||||
{selectedAccepted.length} Item{selectedAccepted.length === 1 ? '' : 's'} {convertLabel}
|
{selectedCommittable.length} Item{selectedCommittable.length === 1 ? '' : 's'}{' '}
|
||||||
|
{convertLabel}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<p className="muted backlog-sprint-planning__hint">
|
<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>
|
</p>
|
||||||
</div>
|
</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." />}
|
{items.length === 0 && <EmptyState message="Backlog ist leer." />}
|
||||||
|
|
||||||
<ul className="item-list backlog-reorder-list">
|
<ul className="item-list backlog-reorder-list">
|
||||||
|
|
@ -262,7 +273,7 @@ export function BacklogSection({
|
||||||
⋮⋮
|
⋮⋮
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{showSprintPlanning && canManage && item.status === 'accepted' && (
|
{showSprintPlanning && canManage && COMMITTABLE_STATUSES.has(item.status) && (
|
||||||
<label className="backlog-select-checkbox">
|
<label className="backlog-select-checkbox">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|
@ -304,14 +315,14 @@ export function BacklogSection({
|
||||||
<PriorityBadge priority={item.priority} />
|
<PriorityBadge priority={item.priority} />
|
||||||
{canManage && item.status !== 'converted' && (
|
{canManage && item.status !== 'converted' && (
|
||||||
<>
|
<>
|
||||||
{item.status === 'accepted' && (
|
{COMMITTABLE_STATUSES.has(item.status) && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-primary btn-sm"
|
className="btn btn-primary btn-sm"
|
||||||
onClick={() => handleSingleConvert(item.id)}
|
onClick={() => handleSingleConvert(item.id)}
|
||||||
disabled={busy || (showSprintPlanning && !sprintTargetId)}
|
disabled={busy || (showSprintPlanning && !sprintTargetId)}
|
||||||
>
|
>
|
||||||
{convertLabel}
|
{showSprintPlanning ? convertLabel : 'In Arbeitspaket umwandeln'}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -670,6 +670,18 @@
|
||||||
background: var(--jk-surface);
|
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 {
|
.backlog-sprint-planning {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user