From 52d121269195f0e799d0ab4241e4facc3c7c0596 Mon Sep 17 00:00:00 2001 From: soryu Date: Mon, 19 Jan 2026 17:55:22 +0000 Subject: Add right-click context menu for contracts on contracts and board pages (#8) Implement a reusable ContractContextMenu component that provides: - Mark as Complete/Active/Archive status actions (conditionally shown) - Go to Supervisor Task link (when supervisor exists) - Delete action with confirmation Integrate context menu into: - ContractList.tsx on the contracts page - WorkflowBoard on the workflow/board page via PhaseColumn and WorkflowContractCard Features match ElementContextMenu patterns: - Fixed positioning with z-50 - Click outside and Escape key close handlers - Viewport overflow prevention - Dark theme colors (#0a1628, #0d1b2d, #75aafc, #9bc3ff) Co-authored-by: Claude Opus 4.5 --- makima/frontend/src/routes/workflow.tsx | 49 +++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) (limited to 'makima/frontend/src/routes/workflow.tsx') diff --git a/makima/frontend/src/routes/workflow.tsx b/makima/frontend/src/routes/workflow.tsx index cb72e9e..e122092 100644 --- a/makima/frontend/src/routes/workflow.tsx +++ b/makima/frontend/src/routes/workflow.tsx @@ -4,7 +4,7 @@ import { Masthead } from "../components/Masthead"; import { WorkflowBoard } from "../components/workflow/WorkflowBoard"; import { useContracts } from "../hooks/useContracts"; import { useAuth } from "../contexts/AuthContext"; -import type { ContractPhase, ContractStatus } from "../lib/api"; +import type { ContractPhase, ContractStatus, ContractSummary } from "../lib/api"; type StatusFilter = "all" | ContractStatus; @@ -41,7 +41,7 @@ export default function WorkflowPage() { function WorkflowPageContent() { const navigate = useNavigate(); - const { contracts, loading, error, changePhase, saveContract } = useContracts(); + const { contracts, loading, error, changePhase, saveContract, editContract, removeContract } = useContracts(); const [statusFilter, setStatusFilter] = useState("all"); const [isCreating, setIsCreating] = useState(false); const [newContractName, setNewContractName] = useState(""); @@ -68,6 +68,46 @@ function WorkflowPageContent() { [changePhase] ); + // Context menu handlers + const handleContextMarkComplete = useCallback( + async (contract: ContractSummary) => { + await editContract(contract.id, { status: "completed", version: contract.version }); + }, + [editContract] + ); + + const handleContextMarkActive = useCallback( + async (contract: ContractSummary) => { + await editContract(contract.id, { status: "active", version: contract.version }); + }, + [editContract] + ); + + const handleContextArchive = useCallback( + async (contract: ContractSummary) => { + await editContract(contract.id, { status: "archived", version: contract.version }); + }, + [editContract] + ); + + const handleContextDelete = useCallback( + async (contract: ContractSummary) => { + if (confirm(`Are you sure you want to delete "${contract.name}"?`)) { + await removeContract(contract.id); + } + }, + [removeContract] + ); + + const handleContextGoToSupervisor = useCallback( + (contract: ContractSummary) => { + if (contract.supervisorTaskId) { + navigate(`/mesh/${contract.supervisorTaskId}`); + } + }, + [navigate] + ); + const handleCreateContract = useCallback(async () => { if (!newContractName.trim()) return; const contract = await saveContract({ @@ -196,6 +236,11 @@ function WorkflowPageContent() { contracts={filteredContracts} onContractClick={handleContractClick} onPhaseChange={handlePhaseChange} + onMarkComplete={handleContextMarkComplete} + onMarkActive={handleContextMarkActive} + onArchive={handleContextArchive} + onDelete={handleContextDelete} + onGoToSupervisor={handleContextGoToSupervisor} /> )} -- cgit v1.2.3