Some checks failed
Deploy Development / deploy (push) Successful in 48s
Test Suite / pytest-backend (push) Successful in 2m56s
Test Suite / lint-backend (push) Successful in 2s
Test Suite / compose-smoke (push) Has been skipped
Test Suite / k6 /api/health Baseline (push) Successful in 18s
Test Suite / playwright-smoke (push) Has been cancelled
Backlog committet in gewaehlten Sprint, Sprint complete-Endpoint, continuous_product-Ansicht ohne aktiven Sprint. Co-authored-by: Cursor <cursoragent@cursor.com>
195 lines
6.6 KiB
JavaScript
195 lines
6.6 KiB
JavaScript
import { useMemo } from 'react'
|
|
import { Link } from 'react-router-dom'
|
|
import { RequireInitiativeScope } from '../../components/RequireInitiativeScope.jsx'
|
|
import { ScopedInitiativeProvider } from '../../layout/ScopedInitiativeProvider.jsx'
|
|
import { InitiativeActionsHub } from '../../components/InitiativeActionsHub.jsx'
|
|
import { NextActionWidget } from '../../widgets/NextActionWidget.jsx'
|
|
import { LoadingState } from '../../components/LoadingState.jsx'
|
|
import { EmptyState } from '../../components/EmptyState.jsx'
|
|
import { useInitiativeOperations } from '../../context/InitiativeOperationsContext.jsx'
|
|
import { useProgramScope } from '../../context/ProgramScopeContext.jsx'
|
|
import { scopedPath } from '../../utils/routes.js'
|
|
|
|
function WorkSprintInner() {
|
|
const { initiativeId, hrefWithScope } = useProgramScope()
|
|
const ops = useInitiativeOperations()
|
|
const {
|
|
activeWorkCycle,
|
|
sprintActions,
|
|
projects,
|
|
roadmapItems,
|
|
capabilities,
|
|
hideDone,
|
|
setHideDone,
|
|
loading,
|
|
error,
|
|
formBusy,
|
|
showActionForm,
|
|
setShowActionForm,
|
|
editingAction,
|
|
setEditingAction,
|
|
actionContextById,
|
|
actors,
|
|
actorsLoading,
|
|
actorsError,
|
|
actorsUsedFallback,
|
|
reloadActors,
|
|
handleCreateAction,
|
|
handleUpdateAction,
|
|
handleQuickStatus,
|
|
handleCreateBlockerForAction,
|
|
initiative,
|
|
steeringSnapshot,
|
|
steeringSnapshotLoading,
|
|
visibleActions,
|
|
} = ops
|
|
|
|
const defaultWorkCycleId = activeWorkCycle?.id || ''
|
|
|
|
const createAction = useMemo(
|
|
() => async (payload) => {
|
|
await handleCreateAction({
|
|
...payload,
|
|
work_cycle_id: payload.work_cycle_id || defaultWorkCycleId || undefined,
|
|
})
|
|
},
|
|
[handleCreateAction, defaultWorkCycleId],
|
|
)
|
|
|
|
if (loading) {
|
|
return <LoadingState message="Lade Sprint-Backlog …" />
|
|
}
|
|
|
|
const isProductArchetype = initiative?.archetype_key === 'initiative.product'
|
|
|
|
return (
|
|
<>
|
|
{error && <p className="error">{error}</p>}
|
|
|
|
{!activeWorkCycle && isProductArchetype && (
|
|
<>
|
|
<section className="card sprint-context-banner">
|
|
<h2>Product-Ist (ohne aktiven Sprint)</h2>
|
|
<p className="section-lead muted">
|
|
Kein aktiver Sprint — Kairo steuert nach{' '}
|
|
<strong>continuous_product</strong> (wirkungsvollster Schritt). Sprint-Planung
|
|
unter{' '}
|
|
<Link to={hrefWithScope('/plan/sprint')} className="link-inline">
|
|
Plan → Sprint
|
|
</Link>
|
|
.
|
|
</p>
|
|
</section>
|
|
|
|
<NextActionWidget
|
|
scope="initiative"
|
|
initiativeId={initiativeId}
|
|
items={steeringSnapshot?.next_actions}
|
|
loading={steeringSnapshotLoading}
|
|
embedded
|
|
title="Nächster Schritt (Product)"
|
|
subtitle="Empfehlung ohne Sprint-Zeitbox — committete Arbeitspakete im Vorhaben."
|
|
/>
|
|
|
|
<InitiativeActionsHub
|
|
initiativeId={initiativeId}
|
|
actions={visibleActions}
|
|
projects={projects}
|
|
roadmapItems={roadmapItems}
|
|
actionContextById={actionContextById}
|
|
hideDone={hideDone}
|
|
onHideDoneChange={setHideDone}
|
|
showForm={showActionForm}
|
|
onToggleForm={() => setShowActionForm((v) => !v)}
|
|
editingActionId={editingAction?.id}
|
|
onEditAction={setEditingAction}
|
|
onCancelEdit={() => setEditingAction(null)}
|
|
onCreateAction={handleCreateAction}
|
|
onUpdateAction={handleUpdateAction}
|
|
onQuickStatus={handleQuickStatus}
|
|
onCreateBlockerForAction={handleCreateBlockerForAction}
|
|
canManage={capabilities.has('kairo.action.manage')}
|
|
canManageBlocker={capabilities.has('kairo.blocker.manage')}
|
|
formBusy={formBusy}
|
|
actors={actors}
|
|
actorsLoading={actorsLoading}
|
|
actorsError={actorsError}
|
|
actorsUsedFallback={actorsUsedFallback}
|
|
onReloadActors={reloadActors}
|
|
workCycles={ops.workCycles}
|
|
activeWorkCycle={activeWorkCycle}
|
|
sectionTitle="Committete Arbeitspakete"
|
|
sectionLead="Ohne aktiven Sprint — alle offenen Arbeitspakete im Product-Vorhaben."
|
|
/>
|
|
</>
|
|
)}
|
|
|
|
{activeWorkCycle && (
|
|
<>
|
|
<section className="card sprint-context-banner">
|
|
<h2>Sprint-Backlog</h2>
|
|
<p className="section-lead muted">
|
|
<strong>{activeWorkCycle.title}</strong>
|
|
{activeWorkCycle.goal_description && ` — ${activeWorkCycle.goal_description}`}
|
|
{' · '}
|
|
Product Backlog triagierst du unter{' '}
|
|
<Link to={scopedPath('/plan/inbox', { initiativeId })} className="link-inline">
|
|
Plan → Eingang
|
|
</Link>
|
|
.
|
|
</p>
|
|
</section>
|
|
|
|
<NextActionWidget
|
|
scope="initiative"
|
|
initiativeId={initiativeId}
|
|
items={steeringSnapshot?.next_actions}
|
|
loading={steeringSnapshotLoading}
|
|
embedded
|
|
title="Nächster Schritt im Sprint"
|
|
/>
|
|
|
|
<InitiativeActionsHub
|
|
initiativeId={initiativeId}
|
|
actions={sprintActions}
|
|
projects={projects}
|
|
roadmapItems={roadmapItems}
|
|
actionContextById={actionContextById}
|
|
hideDone={hideDone}
|
|
onHideDoneChange={setHideDone}
|
|
showForm={showActionForm}
|
|
onToggleForm={() => setShowActionForm((v) => !v)}
|
|
editingActionId={editingAction?.id}
|
|
onEditAction={setEditingAction}
|
|
onCancelEdit={() => setEditingAction(null)}
|
|
onCreateAction={createAction}
|
|
onUpdateAction={handleUpdateAction}
|
|
onQuickStatus={handleQuickStatus}
|
|
onCreateBlockerForAction={handleCreateBlockerForAction}
|
|
canManage={capabilities.has('kairo.action.manage')}
|
|
canManageBlocker={capabilities.has('kairo.blocker.manage')}
|
|
formBusy={formBusy}
|
|
actors={actors}
|
|
actorsLoading={actorsLoading}
|
|
actorsError={actorsError}
|
|
actorsUsedFallback={actorsUsedFallback}
|
|
onReloadActors={reloadActors}
|
|
workCycles={ops.workCycles}
|
|
activeWorkCycle={activeWorkCycle}
|
|
/>
|
|
</>
|
|
)}
|
|
</>
|
|
)
|
|
}
|
|
|
|
export function WorkSprintPage() {
|
|
return (
|
|
<RequireInitiativeScope lead="Sprint-Backlog ist vorhabenspezifisch — wähle ein Product-Vorhaben im Scope.">
|
|
<ScopedInitiativeProvider>
|
|
<WorkSprintInner />
|
|
</ScopedInitiativeProvider>
|
|
</RequireInitiativeScope>
|
|
)
|
|
}
|