diff options
| author | soryu <soryu@soryu.co> | 2026-01-27 02:56:52 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-27 02:56:52 +0000 |
| commit | ee45906b07d1032afaf8a56cce48826bea0c3f8b (patch) | |
| tree | 21b4c7c628f24708d737e5a7742dc66901ea3e1c | |
| parent | f6d5692eb1e290689df516cec6fe77f07d419783 (diff) | |
| download | soryu-ee45906b07d1032afaf8a56cce48826bea0c3f8b.tar.gz soryu-ee45906b07d1032afaf8a56cce48826bea0c3f8b.zip | |
Fix history page contracts dropdown overflow (#38)
* Add comprehensive Red Team system specification
Defines the adversarial review feature for contracts that monitors work tasks
in real-time to catch quality issues, plan deviations, and standards violations.
Key components specified:
- Contract configuration (red_team_enabled, red_team_prompt)
- Red team task lifecycle and spawning logic
- makima red-team notify CLI command for supervisor alerts
- Task output subscription for real-time monitoring
- Database schema changes (contracts, tasks, notifications table)
- API endpoints for notification and status
- System prompt template for red team behavior
- Security considerations and access control
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Task completion checkpoint
* Task completion checkpoint
* Task completion checkpoint
* Fix history page contracts dropdown overflow
Replace native HTML <select> with custom dropdown component that:
- Uses max-h-[300px] with overflow-y-auto for scrollable list
- Positions with z-50 to not interfere with other elements
- Closes on click outside via mousedown event listener
- Shows chevron indicator with rotation animation
- Maintains dark theme styling with blue accents
- Highlights selected contract with visual feedback
Fixes issue where long contract lists caused page overflow
and obscured date filter inputs.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* [WIP] Heartbeat checkpoint - 2026-01-27 02:48:59 UTC
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
| -rw-r--r-- | makima/frontend/src/components/history/HistoryFilters.tsx | 81 |
1 files changed, 69 insertions, 12 deletions
diff --git a/makima/frontend/src/components/history/HistoryFilters.tsx b/makima/frontend/src/components/history/HistoryFilters.tsx index a1a4945..3be50ad 100644 --- a/makima/frontend/src/components/history/HistoryFilters.tsx +++ b/makima/frontend/src/components/history/HistoryFilters.tsx @@ -1,3 +1,4 @@ +import { useState, useRef, useEffect } from "react"; import type { ContractSummary } from "../../lib/api"; interface HistoryFiltersProps { @@ -21,23 +22,79 @@ export function HistoryFilters({ onDateToChange, totalCount, }: HistoryFiltersProps) { + const [isDropdownOpen, setIsDropdownOpen] = useState(false); + const dropdownRef = useRef<HTMLDivElement>(null); + + // Get the selected contract name for display + const selectedContract = contracts.find((c) => c.id === selectedContractId); + const displayText = selectedContract ? selectedContract.name : "All Contracts"; + + // Close dropdown when clicking outside + useEffect(() => { + function handleClickOutside(event: MouseEvent) { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + setIsDropdownOpen(false); + } + } + + if (isDropdownOpen) { + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + } + }, [isDropdownOpen]); + + const handleSelect = (contractId: string | null) => { + onContractChange(contractId); + setIsDropdownOpen(false); + }; + return ( <div className="shrink-0 flex items-center gap-4 p-3 border border-[rgba(117,170,252,0.15)] bg-[rgba(0,0,0,0.2)]"> {/* Contract filter */} <div className="flex items-center gap-2"> <label className="font-mono text-[10px] text-[#7788aa] uppercase">Contract</label> - <select - value={selectedContractId || ""} - onChange={(e) => onContractChange(e.target.value || null)} - className="font-mono text-xs text-[#9bc3ff] bg-[#0a1525] border border-[rgba(117,170,252,0.25)] px-2 py-1 focus:border-[#3f6fb3] focus:outline-none min-w-[150px]" - > - <option value="">All Contracts</option> - {contracts.map((contract) => ( - <option key={contract.id} value={contract.id}> - {contract.name} - </option> - ))} - </select> + <div className="relative" ref={dropdownRef}> + <button + type="button" + onClick={() => setIsDropdownOpen(!isDropdownOpen)} + className="font-mono text-xs text-[#9bc3ff] bg-[#0a1525] border border-[rgba(117,170,252,0.25)] px-2 py-1 focus:border-[#3f6fb3] focus:outline-none min-w-[150px] text-left flex items-center justify-between gap-2" + > + <span className="truncate">{displayText}</span> + <svg + className={`w-3 h-3 transition-transform ${isDropdownOpen ? "rotate-180" : ""}`} + fill="none" + stroke="currentColor" + viewBox="0 0 24 24" + > + <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /> + </svg> + </button> + {isDropdownOpen && ( + <div className="absolute top-full left-0 mt-1 min-w-[200px] max-h-[300px] overflow-y-auto bg-[#0a1525] border border-[rgba(117,170,252,0.25)] z-50 shadow-lg"> + <button + type="button" + onClick={() => handleSelect(null)} + className={`w-full text-left font-mono text-xs px-2 py-1.5 hover:bg-[rgba(117,170,252,0.1)] transition-colors ${ + selectedContractId === null ? "text-[#75aafc] bg-[rgba(117,170,252,0.05)]" : "text-[#9bc3ff]" + }`} + > + All Contracts + </button> + {contracts.map((contract) => ( + <button + type="button" + key={contract.id} + onClick={() => handleSelect(contract.id)} + className={`w-full text-left font-mono text-xs px-2 py-1.5 hover:bg-[rgba(117,170,252,0.1)] transition-colors ${ + selectedContractId === contract.id ? "text-[#75aafc] bg-[rgba(117,170,252,0.05)]" : "text-[#9bc3ff]" + }`} + > + {contract.name} + </button> + ))} + </div> + )} + </div> </div> {/* Date range */} |
