diff options
Diffstat (limited to 'makima/frontend/src/components/contracts/PhaseDeliverablesPanel.tsx')
| -rw-r--r-- | makima/frontend/src/components/contracts/PhaseDeliverablesPanel.tsx | 339 |
1 files changed, 0 insertions, 339 deletions
diff --git a/makima/frontend/src/components/contracts/PhaseDeliverablesPanel.tsx b/makima/frontend/src/components/contracts/PhaseDeliverablesPanel.tsx deleted file mode 100644 index b2c2e58..0000000 --- a/makima/frontend/src/components/contracts/PhaseDeliverablesPanel.tsx +++ /dev/null @@ -1,339 +0,0 @@ -import { useMemo } from "react"; -import type { ContractWithRelations, ContractPhase, ContractType } from "../../lib/api"; - -// Phase deliverables configuration (mirrors backend phase_guidance.rs) -// IDs must match backend phase_guidance.rs exactly for mark_deliverable_complete -interface PhaseDeliverable { - id: string; // Must match backend deliverable ID - name: string; - priority: "required" | "recommended" | "optional"; - description: string; -} - -interface PhaseConfig { - deliverables: PhaseDeliverable[]; - requiresRepository: boolean; - requiresTasks: boolean; - guidance: string; -} - -// Contract type specific deliverables (must match backend phase_guidance.rs) -type ContractTypeDeliverables = Partial<Record<ContractPhase, PhaseConfig>>; - -const CONTRACT_TYPE_DELIVERABLES: Record<ContractType, ContractTypeDeliverables> = { - simple: { - plan: { - deliverables: [ - { id: "plan-document", name: "Plan", priority: "required", description: "Implementation plan detailing the approach and tasks" }, - ], - requiresRepository: true, - requiresTasks: false, - guidance: "Create a plan document that outlines the implementation approach. A repository must be configured before moving to Execute phase.", - }, - execute: { - deliverables: [ - { id: "pull-request", name: "Pull Request", priority: "required", description: "Pull request with the implemented changes" }, - ], - requiresRepository: true, - requiresTasks: true, - guidance: "Execute the plan and create a PR with the implemented changes. Complete all tasks to finish the contract.", - }, - }, - specification: { - research: { - deliverables: [ - { id: "research-notes", name: "Research Notes", priority: "required", description: "Document findings and insights during research" }, - ], - requiresRepository: false, - requiresTasks: false, - guidance: "Focus on understanding the problem space and document your findings in the Research Notes before moving to Specify phase.", - }, - specify: { - deliverables: [ - { id: "requirements-document", name: "Requirements Document", priority: "required", description: "Define functional and non-functional requirements" }, - ], - requiresRepository: false, - requiresTasks: false, - guidance: "Define what needs to be built with clear requirements in the Requirements Document. Ensure specifications are detailed enough for planning.", - }, - plan: { - deliverables: [ - { id: "plan-document", name: "Plan", priority: "required", description: "Implementation plan detailing the approach and tasks" }, - ], - requiresRepository: true, - requiresTasks: false, - guidance: "Create a plan document that outlines the implementation approach. A repository must be configured before moving to Execute phase.", - }, - execute: { - deliverables: [ - { id: "pull-request", name: "Pull Request", priority: "required", description: "Pull request with the implemented changes" }, - ], - requiresRepository: true, - requiresTasks: true, - guidance: "Execute the plan and create a PR with the implemented changes. Complete all tasks before moving to Review phase.", - }, - review: { - deliverables: [ - { id: "release-notes", name: "Release Notes", priority: "required", description: "Document changes for release communication" }, - ], - requiresRepository: false, - requiresTasks: false, - guidance: "Review completed work and document the release in the Release Notes. The contract can be completed after review.", - }, - }, - execute: { - execute: { - deliverables: [], // No deliverables for execute-only contract type - requiresRepository: true, - requiresTasks: true, - guidance: "Execute the tasks directly. No deliverable documents are required for this contract type.", - }, - }, -}; - -// Get phase config for a specific contract type and phase -function getPhaseConfig(contractType: ContractType, phase: ContractPhase): PhaseConfig { - const typeConfig = CONTRACT_TYPE_DELIVERABLES[contractType]; - const phaseConfig = typeConfig?.[phase]; - - if (phaseConfig) { - return phaseConfig; - } - - // Fallback for unknown phase/type combinations - return { - deliverables: [], - requiresRepository: false, - requiresTasks: false, - guidance: `Unknown phase "${phase}" for contract type "${contractType}"`, - }; -} - -interface DeliverableStatus { - id: string; - name: string; - priority: "required" | "recommended" | "optional"; - description: string; - completed: boolean; - fileId?: string; - actualName?: string; -} - -interface PhaseDeliverablesProps { - contract: ContractWithRelations; - onCreateFile?: (templateId: string, suggestedName: string) => void; -} - -export function PhaseDeliverablesPanel({ contract, onCreateFile }: PhaseDeliverablesProps) { - // Get phase config based on contract type AND phase - const phaseConfig = useMemo( - () => getPhaseConfig(contract.contractType, contract.phase), - [contract.contractType, contract.phase] - ); - - // Calculate deliverable status - const deliverableStatuses = useMemo((): DeliverableStatus[] => { - return phaseConfig.deliverables.map((deliverable) => { - // Find matching file by name similarity - const matchedFile = contract.files.find((f) => { - const nameLower = f.name.toLowerCase(); - const deliverableLower = deliverable.name.toLowerCase(); - return ( - f.contractPhase === contract.phase && - (nameLower.includes(deliverableLower) || deliverableLower.includes(nameLower) || nameLower.includes(deliverable.id.replace("-", " "))) - ); - }); - - return { - ...deliverable, - completed: !!matchedFile, - fileId: matchedFile?.id, - actualName: matchedFile?.name, - }; - }); - }, [contract.files, contract.phase, phaseConfig.deliverables]); - - // Check repository status - const hasRepository = contract.repositories.length > 0; - - // Check task status - const taskStats = useMemo(() => { - const total = contract.tasks.length; - const done = contract.tasks.filter((t) => t.status === "done" || t.status === "merged").length; - const pending = contract.tasks.filter((t) => t.status === "pending").length; - const running = contract.tasks.filter((t) => ["running", "initializing", "starting"].includes(t.status)).length; - const failed = contract.tasks.filter((t) => t.status === "failed").length; - return { total, done, pending, running, failed }; - }, [contract.tasks]); - - // Calculate completion percentage - const completionPercent = useMemo(() => { - let completed = 0; - let total = 0; - - // Count required and recommended deliverables - deliverableStatuses.forEach((s) => { - if (s.priority !== "optional") { - total++; - if (s.completed) completed++; - } - }); - - // Count repository if required - if (phaseConfig.requiresRepository) { - total++; - if (hasRepository) completed++; - } - - // Count tasks if required - if (phaseConfig.requiresTasks && taskStats.total > 0) { - total++; - if (taskStats.done === taskStats.total) completed++; - } - - return total > 0 ? Math.round((completed / total) * 100) : 100; - }, [deliverableStatuses, hasRepository, phaseConfig, taskStats]); - - const priorityColors = { - required: "text-red-400", - recommended: "text-yellow-400", - optional: "text-[#555]", - }; - - return ( - <div className="space-y-4"> - <div className="flex items-center justify-between"> - <h3 className="font-mono text-xs text-[#75aafc] uppercase"> - Phase Deliverables - </h3> - <div className="flex items-center gap-2"> - <div className="w-24 h-1.5 bg-[rgba(117,170,252,0.1)] rounded overflow-hidden"> - <div - className={`h-full transition-all duration-300 ${ - completionPercent === 100 ? "bg-green-400" : "bg-[#75aafc]" - }`} - style={{ width: `${completionPercent}%` }} - /> - </div> - <span className="font-mono text-[10px] text-[#555]">{completionPercent}%</span> - </div> - </div> - - {/* Guidance text */} - <p className="font-mono text-xs text-[#555] italic">{phaseConfig.guidance}</p> - - {/* Deliverables checklist */} - <div className="space-y-2"> - {deliverableStatuses.map((status) => ( - <div - key={status.id} - className={`flex items-center justify-between p-2 border ${ - status.completed - ? "border-green-400/20 bg-green-400/5" - : "border-[rgba(117,170,252,0.15)]" - }`} - > - <div className="flex items-center gap-2"> - <span - className={`font-mono text-xs ${ - status.completed ? "text-green-400" : "text-[#555]" - }`} - > - {status.completed ? "[+]" : "[ ]"} - </span> - <div> - <div className="flex items-center gap-2"> - <span className="font-mono text-xs text-[#dbe7ff]"> - {status.completed ? status.actualName : status.name} - </span> - {!status.completed && ( - <span className={`font-mono text-[9px] uppercase ${priorityColors[status.priority]}`}> - {status.priority} - </span> - )} - </div> - <span className="font-mono text-[10px] text-[#555]"> - {status.description} - </span> - </div> - </div> - {!status.completed && onCreateFile && ( - <button - onClick={() => onCreateFile(status.id, status.name)} - className="px-2 py-1 font-mono text-[10px] text-[#75aafc] border border-[rgba(117,170,252,0.25)] hover:border-[#3f6fb3] transition-colors" - > - Create - </button> - )} - </div> - ))} - </div> - - {/* Repository status */} - {phaseConfig.requiresRepository && ( - <div - className={`flex items-center gap-2 p-2 border ${ - hasRepository - ? "border-green-400/20 bg-green-400/5" - : "border-[rgba(117,170,252,0.15)]" - }`} - > - <span - className={`font-mono text-xs ${ - hasRepository ? "text-green-400" : "text-[#555]" - }`} - > - {hasRepository ? "[+]" : "[ ]"} - </span> - <div> - <span className="font-mono text-xs text-[#dbe7ff]"> - Repository Configured - </span> - {!hasRepository && ( - <span className="font-mono text-[9px] uppercase text-red-400 ml-2"> - required - </span> - )} - </div> - </div> - )} - - {/* Task status */} - {phaseConfig.requiresTasks && ( - <div - className={`flex items-center justify-between p-2 border ${ - taskStats.total > 0 && taskStats.done === taskStats.total - ? "border-green-400/20 bg-green-400/5" - : "border-[rgba(117,170,252,0.15)]" - }`} - > - <div className="flex items-center gap-2"> - <span - className={`font-mono text-xs ${ - taskStats.total > 0 && taskStats.done === taskStats.total - ? "text-green-400" - : "text-[#555]" - }`} - > - {taskStats.total > 0 && taskStats.done === taskStats.total ? "[+]" : "[ ]"} - </span> - <span className="font-mono text-xs text-[#dbe7ff]"> - Tasks Completed - </span> - </div> - {taskStats.total > 0 ? ( - <span className="font-mono text-[10px] text-[#9bc3ff]"> - {taskStats.done}/{taskStats.total} - {taskStats.running > 0 && ` (${taskStats.running} running)`} - {taskStats.failed > 0 && ( - <span className="text-red-400"> ({taskStats.failed} failed)</span> - )} - </span> - ) : ( - <span className="font-mono text-[10px] text-[#555]">No tasks yet</span> - )} - </div> - )} - </div> - ); -} |
