// ======================================== // Hook Card Component // ======================================== // Individual hook display card with actions import { useIntl } from 'react-intl'; import { GitFork, Power, PowerOff, Edit, Trash2, ChevronDown, ChevronUp, } from 'lucide-react'; import { Card } from '@/components/ui/Card'; import { Button } from '@/components/ui/Button'; import { Badge } from '@/components/ui/Badge'; import { cn } from '@/lib/utils'; // ========== Types ========== export type HookTriggerType = 'SessionStart' | 'UserPromptSubmit' | 'PreToolUse' | 'PostToolUse' | 'Stop' | 'Notification' | 'SubagentStart' | 'SubagentStop' | 'PreCompact' | 'SessionEnd' | 'PostToolUseFailure' | 'PermissionRequest'; export interface HookCardData { name: string; description?: string; enabled: boolean; trigger: HookTriggerType; matcher?: string; command?: string; script?: string; } export interface HookCardProps { hook: HookCardData; isExpanded: boolean; onToggleExpand: () => void; onToggle: (hookName: string, enabled: boolean) => void; onEdit: (hook: HookCardData) => void; onDelete: (hookName: string) => void; } // ========== Helper Functions ========== function getTriggerIcon(trigger: HookTriggerType) { switch (trigger) { case 'SessionStart': return '🎬'; case 'UserPromptSubmit': return '⚡'; case 'PreToolUse': return '🔧'; case 'PostToolUse': return '✅'; case 'Stop': return '🛑'; case 'Notification': return '🔔'; case 'SubagentStart': return '🚀'; case 'SubagentStop': return '🏁'; case 'PreCompact': return '📦'; case 'SessionEnd': return '👋'; case 'PostToolUseFailure': return '❌'; case 'PermissionRequest': return '🔐'; default: return '📌'; } } function getTriggerVariant(trigger: HookTriggerType): 'default' | 'secondary' | 'outline' { switch (trigger) { case 'SessionStart': case 'UserPromptSubmit': case 'SubagentStart': return 'default'; case 'PreToolUse': case 'Stop': case 'PreCompact': case 'PermissionRequest': return 'secondary'; case 'PostToolUse': case 'Notification': case 'SubagentStop': case 'SessionEnd': case 'PostToolUseFailure': return 'outline'; default: return 'outline'; } } // ========== Component ========== // ========== Hook Name Translation ========== /** * Get translated hook name if available * Falls back to original name if no translation exists */ function getHookDisplayName(name: string, formatMessage: (msg: { id: string }) => string): string { const translationKey = `cliHooks.templates.templates.${name}.name`; // Try to get translation, fallback to original name try { const translated = formatMessage({ id: translationKey }); // If translation returns the key itself, no translation exists if (translated && !translated.includes('cliHooks.templates.templates')) { return translated; } } catch { // Translation not found } return name; } // ========== Component ========== export function HookCard({ hook, isExpanded, onToggleExpand, onToggle, onEdit, onDelete, }: HookCardProps) { const { formatMessage } = useIntl(); // Get translated hook name const displayName = getHookDisplayName(hook.name, formatMessage); const handleToggle = () => { onToggle(hook.name, !hook.enabled); }; const handleEdit = () => { onEdit(hook); }; const handleDelete = () => { if (confirm(formatMessage({ id: 'cliHooks.actions.deleteConfirm' }, { hookName: hook.name }))) { onDelete(hook.name); } }; return ( {/* Header */}
{hook.name} {getTriggerIcon(hook.trigger)} {formatMessage({ id: `cliHooks.trigger.${hook.trigger}` })} {hook.enabled ? formatMessage({ id: 'common.status.enabled' }) : formatMessage({ id: 'common.status.disabled' }) }
{hook.description && (

{hook.description}

)}
{/* Action Buttons */}
{/* Expanded Content */} {isExpanded && (
{hook.description && (

{hook.description}

)}

{hook.matcher || formatMessage({ id: 'cliHooks.allTools' })}

{hook.command || hook.script || 'N/A'}

)}
); } export default HookCard;