import { useCallback, useEffect, useState } from 'react' import { Link, useParams } from 'react-router-dom' import { getAction } from '../api/actions.js' import { getInitiativeSteeringSnapshot, listInitiativeActions, } from '../api/initiatives.js' import { getInitiativeExecutionGraphState } from '../api/executionPlan.js' import { listInitiativeProjects } from '../api/projects.js' import { listInitiativeRoadmapItems } from '../api/roadmap.js' import { updateAction, setActionAssignments } from '../api/actions.js' import { createInitiativeBlocker } from '../api/blockers.js' import { ActionHubCard } from '../components/ActionHubCard.jsx' import { ActionDependenciesSection } from '../components/ActionDependenciesSection.jsx' import { ActionForm } from '../components/ActionForm.jsx' import { TasksSection } from '../components/TasksSection.jsx' import { ErrorState } from '../components/ErrorState.jsx' import { LoadingState } from '../components/LoadingState.jsx' import { useInitiativeOperations } from '../context/InitiativeOperationsContext.jsx' import { useProgramScope } from '../context/ProgramScopeContext.jsx' import { useCapabilities } from '../hooks/useCapabilities.js' import { useActors } from '../hooks/useActors.js' import { recordRecentObject } from '../utils/recentObjects.js' import { actionPath, scopedPath } from '../utils/routes.js' function ActionDetailBody({ action, context, editing, onEdit, onCancelEdit, onSubmit, onQuickStatus, onCreateBlocker, formBusy, capabilities, actorsState, projects = [], roadmapItems = [], allActions = [], executionGraph = null, }) { if (editing) { return ( ) } return ( <> ) } function ActionDetailStandalone() { const { actionId } = useParams() const { applyFromAction } = useProgramScope() const { capabilities } = useCapabilities() const actorsState = useActors() const [action, setAction] = useState(null) const [projects, setProjects] = useState([]) const [roadmapItems, setRoadmapItems] = useState([]) const [allActions, setAllActions] = useState([]) const [executionGraph, setExecutionGraph] = useState(null) const [context, setContext] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [editing, setEditing] = useState(false) const [formBusy, setFormBusy] = useState(false) const load = useCallback(async () => { setLoading(true) setError(null) try { const actionData = await getAction(actionId) setAction(actionData) applyFromAction(actionData) recordRecentObject({ type: 'action', id: actionData.id, title: actionData.title, href: actionPath(actionData.id), initiativeId: actionData.initiative_id, }) const [snap, projectData, roadmapData, actionList, graphState] = await Promise.all([ getInitiativeSteeringSnapshot(actionData.initiative_id), listInitiativeProjects(actionData.initiative_id).catch(() => []), listInitiativeRoadmapItems(actionData.initiative_id).catch(() => []), listInitiativeActions(actionData.initiative_id).catch(() => []), getInitiativeExecutionGraphState(actionData.initiative_id).catch(() => null), ]) setProjects(projectData) setRoadmapItems(roadmapData) setAllActions(Array.isArray(actionList) ? actionList : []) setExecutionGraph(graphState) setContext((snap.actions || []).find((a) => a.id === actionId) || null) } catch (err) { setError(err.message) } finally { setLoading(false) } }, [actionId, applyFromAction]) useEffect(() => { load() }, [load]) async function handleSubmit(payload) { setFormBusy(true) try { await updateAction(action.id, { title: payload.title, description: payload.description, status: payload.status, priority: payload.priority, due_at: payload.due_at, clear_due_at: !payload.due_at, project_id: payload.project_id, clear_project: payload.project_id === '' || payload.project_id === null, roadmap_item_id: payload.roadmap_item_id, clear_roadmap_item: payload.roadmap_item_id === '' || payload.roadmap_item_id === null, }) if (capabilities.has('kairo.action.manage')) { await setActionAssignments(action.id, payload.assigned_actor_ids || []) } setEditing(false) await load() } catch (err) { setError(err.message) } finally { setFormBusy(false) } } async function handleQuickStatus(status) { if (!capabilities.has('kairo.action.manage')) return try { await updateAction(action.id, { status }) await load() } catch (err) { setError(err.message) } } async function handleCreateBlocker() { if (!capabilities.has('kairo.blocker.manage')) return setFormBusy(true) try { await createInitiativeBlocker(action.initiative_id, { title: 'Blocker', action_id: action.id, set_action_blocked: true, }) await load() } catch (err) { setError(err.message) } finally { setFormBusy(false) } } if (loading) { return (
) } if (error || !action) { return (
) } return (

Arbeitspaket

setEditing(true)} onCancelEdit={() => setEditing(false)} onSubmit={handleSubmit} onQuickStatus={handleQuickStatus} onCreateBlocker={handleCreateBlocker} formBusy={formBusy} capabilities={capabilities} actorsState={actorsState} projects={projects} roadmapItems={roadmapItems} allActions={allActions} executionGraph={executionGraph} />
) } function ActionDetailNested() { const { actionId } = useParams() const ops = useInitiativeOperations() const action = ops.actions.find((a) => a.id === actionId) const context = ops.actionContextById[actionId] const [editing, setEditing] = useState(false) const [executionGraph, setExecutionGraph] = useState(null) useEffect(() => { if (!ops.initiativeId) { setExecutionGraph(null) return undefined } let cancelled = false getInitiativeExecutionGraphState(ops.initiativeId) .then((state) => { if (!cancelled) setExecutionGraph(state) }) .catch(() => { if (!cancelled) setExecutionGraph(null) }) return () => { cancelled = true } }, [ops.initiativeId, ops.actions.length]) if (!action) { return } return (

Arbeitspaket

setEditing(true)} onCancelEdit={() => setEditing(false)} onSubmit={(payload) => ops.handleUpdateAction(action.id, payload)} onQuickStatus={(status) => ops.handleQuickStatus(action, status)} onCreateBlocker={() => ops.handleCreateBlockerForAction(action.id)} formBusy={ops.formBusy} capabilities={ops.capabilities} actorsState={{ actors: ops.actors, loading: ops.actorsLoading, error: ops.actorsError, usedFallback: ops.actorsUsedFallback, reload: ops.reloadActors, }} projects={ops.projects} roadmapItems={ops.roadmapItems} allActions={ops.actions} executionGraph={executionGraph} />
) } export function ActionDetailPage({ nested = false }) { if (nested) { return } return }