Kairo-Jinkendo/frontend/src/components/SteeringProposalsPanel.jsx
Lars b747200f3a
All checks were successful
Deploy Development / deploy (push) Successful in 46s
Test Suite / pytest-backend (push) Successful in 4m13s
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 19s
Test Suite / playwright-smoke (push) Successful in 12s
feat(steering): K-Ext-2 Attention-Registry, Gate/Intake-Proposals, generische UI
Methodenuebergreifende Provider auf Kernel v0.3; verbindliche Coding Rules fuer Agenten in ADP und .cursor/rules.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-27 11:48:10 +02:00

108 lines
3.9 KiB
JavaScript

import {
PROPOSAL_UI_CONFIG,
filterSprintProposals,
listProposalKeys,
proposalReasonLabel,
} from '../utils/steeringProposals.js'
import { backlogKindLabel, resolveBacklogVocabulary } from '../utils/resolveBacklogVocabulary.js'
import { PriorityBadge } from './PriorityBadge.jsx'
export function SteeringProposalsPanel({
proposalsByKey = {},
proposalKeys = null,
backlogVocabulary = null,
canManage = false,
onAcceptBacklogProposal,
busy = false,
filterContext = {},
}) {
const vocabulary = resolveBacklogVocabulary(backlogVocabulary)
const keys = proposalKeys || listProposalKeys(proposalsByKey)
if (!keys.length) {
return null
}
return (
<>
{keys.map((proposalKey) => {
const config = PROPOSAL_UI_CONFIG[proposalKey] || {
title: proposalKey,
lead: 'Steuerungsvorschlag',
acceptLabel: 'Übernehmen',
scopeTypes: ['backlog_item'],
}
let items = proposalsByKey[proposalKey] || []
if (proposalKey === 'sprint_commit' && filterContext.workCycleId) {
items = filterSprintProposals(items, filterContext.workCycleId)
}
if (!items.length) return null
const ranker = items[0]?.ranker_key || 'heuristic_v0'
return (
<section key={proposalKey} className="card steering-proposals">
<div className="section-header">
<div>
<h2>{config.title}</h2>
<p className="section-lead muted">
{config.lead} Ranker: {ranker}.
</p>
</div>
</div>
<ol className="item-list steering-proposals__list">
{items.map((proposal) => (
<li
key={`${proposalKey}-${proposal.scope_type}-${proposal.scope_id}`}
className="list-item card-list-item steering-proposal"
>
<div className="list-item-main">
<strong>
{proposal.rank}. {proposal.title}
</strong>
<p className="list-item-sub muted">{proposalReasonLabel(proposal)}</p>
{proposal.dependency_blocked && (
<p className="list-item-sub muted steering-proposal__blocked">
Abhängigkeit offen
</p>
)}
{proposal.scope_type === 'roadmap_item' && (
<p className="list-item-sub muted">
Gate ohne Plan Arbeitspaket anlegen oder Eingang committen
</p>
)}
</div>
<div className="list-item-meta action-controls">
{proposal.item_kind && (
<span className="badge badge--kind muted">
{backlogKindLabel(vocabulary, proposal.item_kind)}
</span>
)}
{proposal.priority && <PriorityBadge priority={proposal.priority} />}
{canManage
&& proposal.scope_type === 'backlog_item'
&& config.scopeTypes.includes('backlog_item') && (
<button
type="button"
className="btn btn-primary btn-sm"
disabled={busy || proposal.dependency_blocked}
onClick={() =>
onAcceptBacklogProposal?.(proposal.scope_id, {
work_cycle_id: proposal.work_cycle_id,
proposal_key: proposalKey,
})
}
>
{config.acceptLabel}
</button>
)}
</div>
</li>
))}
</ol>
</section>
)
})}
</>
)
}