-
Unverknüpft
-
- {counts.unlinked_blockers} Blocker, {counts.unlinked_evidence} Evidence
-
+
+ {next_actions.length > 0 && (
+
+
Nächste Schritte
+
+ {next_actions.map((item, i) => (
+ -
+
+ {i + 1}
+ {item.title}
+
+ {NEXT_ACTION_KIND_LABELS[item.kind] || item.kind}
+ {item.recommended_action ? ` — ${item.recommended_action}` : ''}
+
+
+
+ ))}
+
)}
-
-
- Steuerungszustand über Standard Lifecycle
- {lifecycle_state ? ` (${lifecycle_state})` : ''}.
-
+ {upcoming_milestones.length > 0 && (
+
+
Meilenstein-Horizont
+
+
+ )}
+
+
+ {(counts.unlinked_blockers > 0 || counts.unlinked_evidence > 0) && (
+
+ {counts.unlinked_blockers > 0 && `${counts.unlinked_blockers} Blocker ohne Maßnahme`}
+ {counts.unlinked_blockers > 0 && counts.unlinked_evidence > 0 && ' · '}
+ {counts.unlinked_evidence > 0 && `${counts.unlinked_evidence} Nachweise ohne Maßnahme`}
+ {' — unter „Erweitert“ verknüpfen oder aufräumen.'}
+
+ )}
)
}
diff --git a/frontend/src/pages/InitiativeDetailPage.jsx b/frontend/src/pages/InitiativeDetailPage.jsx
index 6d66027..7d7d833 100644
--- a/frontend/src/pages/InitiativeDetailPage.jsx
+++ b/frontend/src/pages/InitiativeDetailPage.jsx
@@ -50,10 +50,8 @@ import {
updateRecurring,
deleteRecurring,
} from '../api/recurring.js'
-import { ACTION_STATUSES, ACTION_STATUS_LABELS } from '../constants/status.js'
import { StatusBadge } from '../components/StatusBadge.jsx'
import { PriorityBadge } from '../components/PriorityBadge.jsx'
-import { ActionForm } from '../components/ActionForm.jsx'
import { BlockersSection } from '../components/BlockersSection.jsx'
import { BacklogSection } from '../components/BacklogSection.jsx'
import { MilestonesSection } from '../components/MilestonesSection.jsx'
@@ -62,8 +60,9 @@ import { DecisionsSection } from '../components/DecisionsSection.jsx'
import { ReviewsSection } from '../components/ReviewsSection.jsx'
import { RecurringSection } from '../components/RecurringSection.jsx'
import { SteeringSnapshotPanel } from '../components/SteeringSnapshotPanel.jsx'
+import { InitiativeActionsHub } from '../components/InitiativeActionsHub.jsx'
+import { CollapsibleSection } from '../components/CollapsibleSection.jsx'
import { listSteeringMethods, updateInitiativeSteeringMethod } from '../api/steering.js'
-import { EmptyState } from '../components/EmptyState.jsx'
import { ErrorState } from '../components/ErrorState.jsx'
import { LoadingState } from '../components/LoadingState.jsx'
import { useCapabilities } from '../hooks/useCapabilities.js'
@@ -165,6 +164,20 @@ export function InitiativeDetailPage() {
(steeringSnapshot?.actions || []).map((a) => [a.id, a])
)
+ const unlinkedBlockers = blockers.filter((b) => !b.action_id)
+
+ const advancedSummary = (() => {
+ const c = steeringSnapshot?.counts
+ const parts = []
+ if (backlogItems.length) parts.push(`${backlogItems.length} Backlog`)
+ if (decisions.length) parts.push(`${decisions.length} Entscheidungen`)
+ if (recurringItems.length) parts.push(`${recurringItems.length} Wiederkehrend`)
+ if (unlinkedBlockers.length) parts.push(`${unlinkedBlockers.length} lose Blocker`)
+ if (c?.unlinked_evidence) parts.push(`${c.unlinked_evidence} lose Nachweise`)
+ if (reviews.length) parts.push(`${reviews.length} Reviews`)
+ return parts.length ? parts.join(' · ') : 'Backlog, Entscheidungen, Nachweise …'
+ })()
+
async function handleMethodChange(methodKey) {
setMethodBusy(true)
try {
@@ -523,140 +536,32 @@ export function InitiativeDetailPage() {
/>
)}
-
-
-
Maßnahmen
-
-
- {capabilities.has('kairo.action.manage') && (
-
- )}
-
-
-
- {showActionForm && (
-
-
setShowActionForm(false)}
- busy={formBusy}
- submitLabel="Maßnahme anlegen"
- />
-
- )}
-
- {visibleActions.length === 0 && (
-
- )}
-
-
- {visibleActions.map((action) => {
- const ctx = actionContextById[action.id]
- return (
- -
- {editingAction === action.id ? (
- handleUpdateAction(action.id, payload)}
- onCancel={() => setEditingAction(null)}
- busy={formBusy}
- submitLabel="Speichern"
- />
- ) : (
- <>
-
-
{action.title}
- {action.description && (
-
{action.description}
- )}
- {action.assigned_actor_ids?.length > 0 && (
-
- Zugewiesen: {action.assigned_actor_ids.length} Actor(s)
-
- )}
- {action.due_at && (
-
- Fällig: {new Date(action.due_at).toLocaleString('de-DE')}
-
- )}
- {ctx && (ctx.open_blocker_count > 0 || ctx.evidence?.length > 0 || ctx.reviews?.length > 0) && (
-
- {ctx.open_blocker_count > 0 && `${ctx.open_blocker_count} Blocker · `}
- {ctx.evidence?.length > 0 && `${ctx.evidence.length} Evidence · `}
- {ctx.reviews?.length > 0 && `${ctx.reviews.length} Review(s)`}
-
- )}
-
-
-
-
- {capabilities.has('kairo.action.manage') && (
- <>
-
- {capabilities.has('kairo.blocker.manage') && action.status !== 'done' && (
-
- )}
-
- >
- )}
-
- >
- )}
-
- )
- })}
-
-
+
{
+ setShowActionForm((v) => !v)
+ setEditingAction(null)
+ }}
+ editingActionId={editingAction}
+ 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}
+ />
{capabilities.has('kairo.initiative.read') && (
- )}
-
- {capabilities.has('kairo.initiative.read') && (
-
- )}
-
- {capabilities.has('kairo.initiative.read') && (
-
- )}
-
- {capabilities.has('kairo.initiative.read') && (
-
- )}
-
- {capabilities.has('kairo.initiative.read') && (
-
- )}
-
- {capabilities.has('kairo.initiative.read') && (
-
+
+
+
+
+
+
+
+
+
+
)}
)
diff --git a/frontend/src/styles/components.css b/frontend/src/styles/components.css
index 53aa74d..abfa0b2 100644
--- a/frontend/src/styles/components.css
+++ b/frontend/src/styles/components.css
@@ -690,3 +690,280 @@
.action-links {
font-size: 0.85rem;
}
+
+/* AP1.1b — Initiative detail steering surface */
+
+.section-lead {
+ margin: 0.25rem 0 0;
+ font-size: 0.875rem;
+ max-width: 42rem;
+}
+
+.steering-snapshot--hero {
+ border-color: var(--jk-accent-muted, #dbeafe);
+ background: linear-gradient(
+ 180deg,
+ var(--jk-surface-raised, #f8fafc) 0%,
+ var(--jk-surface, #fff) 100%
+ );
+}
+
+.steering-hero-header {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 0.75rem 1rem;
+ margin-bottom: 0.75rem;
+}
+
+.steering-hero-kicker {
+ margin: 0;
+ font-size: 0.75rem;
+ font-weight: 600;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+ color: var(--jk-accent, #2563eb);
+}
+
+.steering-hero-title {
+ margin: 0.15rem 0 0;
+ font-size: 1.15rem;
+ line-height: 1.35;
+}
+
+.steering-lifecycle-badge {
+ flex-shrink: 0;
+}
+
+.steering-hero-toolbar {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 0.75rem 1.25rem;
+ margin-bottom: 0.75rem;
+}
+
+.steering-stat-pills {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+.steering-stat-pill {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ min-width: 3.25rem;
+ padding: 0.35rem 0.6rem;
+ border-radius: 0.5rem;
+ background: var(--jk-surface, #fff);
+ border: 1px solid var(--jk-border, #e5e7eb);
+}
+
+.steering-stat-pill--warn {
+ border-color: var(--jk-warning-border, #fcd34d);
+ background: var(--jk-warning-bg, #fffbeb);
+}
+
+.steering-stat-pill-value {
+ font-weight: 700;
+ font-size: 1rem;
+ line-height: 1.2;
+}
+
+.steering-stat-pill-label {
+ font-size: 0.7rem;
+ color: var(--jk-text-muted, #6b7280);
+}
+
+.steering-hero-columns {
+ display: grid;
+ gap: 1rem;
+}
+
+@media (min-width: 768px) {
+ .steering-hero-columns {
+ grid-template-columns: 1fr 1fr;
+ }
+}
+
+.steering-unlinked-hint {
+ margin: 0.75rem 0 0;
+ font-size: 0.85rem;
+}
+
+.initiative-actions-hub {
+ border-width: 2px;
+}
+
+.action-hub-grid {
+ display: grid;
+ gap: 0.75rem;
+}
+
+.action-hub-card {
+ border: 1px solid var(--jk-border, #e5e7eb);
+ border-radius: 0.65rem;
+ padding: 0.85rem 1rem;
+ background: var(--jk-surface, #fff);
+}
+
+.action-hub-card--blocked {
+ border-color: var(--jk-warning-border, #fbbf24);
+ background: var(--jk-warning-bg, #fffbeb);
+}
+
+.action-hub-card--editing {
+ padding: 0.5rem;
+}
+
+.action-hub-card-header {
+ margin-bottom: 0.5rem;
+}
+
+.action-hub-card-title-row {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 0.5rem;
+}
+
+.action-hub-card-title {
+ margin: 0;
+ font-size: 1rem;
+ font-weight: 600;
+}
+
+.action-hub-card-badges {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.35rem;
+}
+
+.action-hub-card-desc {
+ margin: 0.35rem 0 0;
+ font-size: 0.9rem;
+ color: var(--jk-text, #111);
+}
+
+.action-hub-card-meta {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.75rem;
+ margin-top: 0.35rem;
+ font-size: 0.8rem;
+}
+
+.action-hub-linked {
+ margin-top: 0.65rem;
+ padding-top: 0.65rem;
+ border-top: 1px dashed var(--jk-border, #e5e7eb);
+}
+
+.action-hub-linked-title {
+ margin: 0 0 0.35rem;
+ font-size: 0.75rem;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.03em;
+ color: var(--jk-text-muted, #6b7280);
+}
+
+.action-hub-linked-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: grid;
+ gap: 0.35rem;
+}
+
+.action-hub-linked-list li {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 0.35rem;
+ font-size: 0.875rem;
+}
+
+.action-hub-card-actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+ margin-top: 0.75rem;
+ padding-top: 0.65rem;
+ border-top: 1px solid var(--jk-border, #e5e7eb);
+}
+
+.btn-sm {
+ padding: 0.25rem 0.55rem;
+ font-size: 0.8rem;
+}
+
+.card--secondary {
+ background: var(--jk-surface-raised, #f9fafb);
+}
+
+.milestone-form textarea {
+ min-height: 4.5rem;
+ resize: vertical;
+}
+
+.collapsible-section {
+ padding: 0;
+ overflow: hidden;
+}
+
+.collapsible-section-trigger {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 0.5rem 1rem;
+ width: 100%;
+ padding: 1rem 1.15rem;
+ border: none;
+ background: transparent;
+ text-align: left;
+ cursor: pointer;
+ font: inherit;
+ color: inherit;
+}
+
+.collapsible-section-trigger:hover {
+ background: var(--jk-surface-raised, #f9fafb);
+}
+
+.collapsible-section-title {
+ font-size: 1.05rem;
+ font-weight: 600;
+}
+
+.collapsible-section-summary {
+ flex: 1;
+ font-size: 0.85rem;
+ min-width: 8rem;
+}
+
+.collapsible-section-chevron {
+ margin-left: auto;
+ color: var(--jk-text-muted, #6b7280);
+}
+
+.collapsible-section-body {
+ padding: 0 1rem 1rem;
+}
+
+.initiative-advanced-stack {
+ display: grid;
+ gap: 0.75rem;
+}
+
+.initiative-advanced-stack .card {
+ box-shadow: none;
+ border-style: dashed;
+}
+