summaryrefslogtreecommitdiff
path: root/makima/frontend/src/components/mesh
diff options
context:
space:
mode:
Diffstat (limited to 'makima/frontend/src/components/mesh')
-rw-r--r--makima/frontend/src/components/mesh/TaskOutput.tsx66
1 files changed, 66 insertions, 0 deletions
diff --git a/makima/frontend/src/components/mesh/TaskOutput.tsx b/makima/frontend/src/components/mesh/TaskOutput.tsx
index d53429d..7140c8a 100644
--- a/makima/frontend/src/components/mesh/TaskOutput.tsx
+++ b/makima/frontend/src/components/mesh/TaskOutput.tsx
@@ -2,6 +2,11 @@ import { useRef, useEffect, useState, useCallback } from "react";
import { SimpleMarkdown } from "../SimpleMarkdown";
import type { TaskOutputEvent } from "../../hooks/useTaskSubscription";
import { sendTaskMessage } from "../../lib/api";
+import {
+ PhaseConfirmationInline,
+ type PhaseConfirmationData,
+} from "../contracts/PhaseConfirmationModal";
+import type { ContractPhase } from "../../lib/api";
interface TaskOutputProps {
/** Array of parsed output events from the backend */
@@ -312,6 +317,15 @@ function OutputEntryRenderer({ entry, pendingQuestionIds, onAnswerQuestion }: Ou
/>
);
+ case "phase_confirmation":
+ return (
+ <PhaseConfirmationEntry
+ entry={entry}
+ pendingQuestionIds={pendingQuestionIds}
+ onAnswerQuestion={onAnswerQuestion}
+ />
+ );
+
default:
return null;
}
@@ -520,3 +534,55 @@ function AuthRequiredEntry({ entry }: { entry: TaskOutputEvent }) {
</div>
);
}
+
+/** Entry for phase transition confirmations */
+function PhaseConfirmationEntry({
+ entry,
+ pendingQuestionIds,
+ onAnswerQuestion,
+}: {
+ entry: TaskOutputEvent;
+ pendingQuestionIds?: Set<string>;
+ onAnswerQuestion?: (questionId: string, response: string) => Promise<void>;
+}) {
+ const questionId = entry.toolInput?.question_id as string;
+ const currentPhase = entry.toolInput?.current_phase as ContractPhase;
+ const nextPhase = entry.toolInput?.next_phase as ContractPhase;
+ const contractId = entry.toolInput?.contract_id as string;
+ const contractName = entry.toolInput?.contract_name as string | undefined;
+ const summary = entry.toolInput?.summary as string | undefined;
+ const deliverables = entry.toolInput?.deliverables as
+ | Array<{ name: string; completed: boolean }>
+ | undefined;
+
+ const isPending = pendingQuestionIds?.has(questionId) ?? false;
+
+ const data: PhaseConfirmationData = {
+ questionId,
+ contractId,
+ contractName,
+ currentPhase,
+ nextPhase,
+ summary,
+ deliverables,
+ };
+
+ const handleApprove = async (qId: string) => {
+ if (!onAnswerQuestion) return;
+ await onAnswerQuestion(qId, "APPROVE");
+ };
+
+ const handleRequestChanges = async (qId: string, feedback: string) => {
+ if (!onAnswerQuestion) return;
+ await onAnswerQuestion(qId, `CHANGES_REQUESTED: ${feedback}`);
+ };
+
+ return (
+ <PhaseConfirmationInline
+ data={data}
+ isPending={isPending}
+ onApprove={handleApprove}
+ onRequestChanges={handleRequestChanges}
+ />
+ );
+}