/** * TriggersPanel - ZCLAW Triggers Management UI * * Displays available ZCLAW Triggers and allows creating and toggling them. */ import { useState, useEffect, useCallback } from 'react'; import { useHandStore } from '../store/handStore'; import type { Trigger } from '../store/handStore'; import { CreateTriggerModal } from './CreateTriggerModal'; import { Zap, RefreshCw, Plus, Globe, Bell, MessageSquare, X, } from 'lucide-react'; // === Trigger Type Config === const TRIGGER_TYPE_CONFIG: Record = { webhook: { icon: Globe, label: 'Webhook', color: 'text-blue-500' }, event: { icon: Bell, label: '事件', color: 'text-amber-500' }, message: { icon: MessageSquare, label: '消息', color: 'text-green-500' }, schedule: { icon: Zap, label: '定时', color: 'text-purple-500' }, file: { icon: Zap, label: '文件', color: 'text-cyan-500' }, manual: { icon: Zap, label: '手动', color: 'text-gray-500' }, }; interface TriggerCardProps { trigger: Trigger; onToggle: (id: string, enabled: boolean) => Promise; onDelete: (id: string) => Promise; isToggling: boolean; isDeleting: boolean; } function TriggerCard({ trigger, onToggle, onDelete, isToggling, isDeleting }: TriggerCardProps) { const handleToggle = async () => { await onToggle(trigger.id, !trigger.enabled); }; const handleDelete = async () => { if (confirm(`确定要删除触发器 "${trigger.id}" 吗?`)) { await onDelete(trigger.id); } }; const typeConfig = TRIGGER_TYPE_CONFIG[trigger.type] || { icon: Zap, label: trigger.type, color: 'text-gray-500' }; const TypeIcon = typeConfig.icon; return (

{trigger.id}

{typeConfig.label} {trigger.enabled ? '已启用' : '已禁用'}
); } export function TriggersPanel() { const triggers = useHandStore((s) => s.triggers); const loadTriggers = useHandStore((s) => s.loadTriggers); const updateTrigger = useHandStore((s) => s.updateTrigger); const deleteTrigger = useHandStore((s) => s.deleteTrigger); const isLoading = useHandStore((s) => s.isLoading); const [togglingTrigger, setTogglingTrigger] = useState(null); const [deletingTrigger, setDeletingTrigger] = useState(null); const [refreshing, setRefreshing] = useState(false); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); useEffect(() => { loadTriggers(); }, [loadTriggers]); const handleToggle = useCallback(async (id: string, enabled: boolean) => { setTogglingTrigger(id); try { await updateTrigger(id, { enabled }); await loadTriggers(); } catch (error) { console.error('Failed to toggle trigger:', error); } finally { setTogglingTrigger(null); } }, [updateTrigger, loadTriggers]); const handleDelete = useCallback(async (id: string) => { setDeletingTrigger(id); try { await deleteTrigger(id); await loadTriggers(); } catch (error) { console.error('Failed to delete trigger:', error); } finally { setDeletingTrigger(null); } }, [deleteTrigger, loadTriggers]); const handleRefresh = useCallback(async () => { setRefreshing(true); try { await loadTriggers(); } finally { setRefreshing(false); } }, [loadTriggers]); const handleCreateSuccess = useCallback(() => { loadTriggers(); }, [loadTriggers]); if (isLoading && triggers.length === 0) { return (
加载中...
); } const enabledCount = triggers.filter(t => t.enabled).length; const totalCount = triggers.length; return ( <>

事件触发器

{enabledCount}/{totalCount} 已启用
{triggers.length === 0 ? (

暂无事件触发器

事件触发器在系统事件(如收到消息、文件更改或 API webhook)发生时触发代理执行。

) : (
{triggers.map((trigger) => ( ))}
)}
setIsCreateModalOpen(false)} onSuccess={handleCreateSuccess} /> ); } export default TriggersPanel;