summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-27 02:56:52 +0000
committerGitHub <noreply@github.com>2026-01-27 02:56:52 +0000
commitee45906b07d1032afaf8a56cce48826bea0c3f8b (patch)
tree21b4c7c628f24708d737e5a7742dc66901ea3e1c
parentf6d5692eb1e290689df516cec6fe77f07d419783 (diff)
downloadsoryu-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.tsx81
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 */}