feat(automation): complete unified automation system redesign

Phase 4 completion:
- Add ApprovalQueue component for managing pending approvals
- Add ExecutionResult component for displaying hand/workflow results
- Update Sidebar navigation to use unified AutomationPanel
- Replace separate 'hands' and 'workflow' tabs with single 'automation' tab
- Fix TypeScript type safety issues with unknown types in JSX expressions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-03-18 17:12:05 +08:00
parent 3a7631e035
commit 3518fc8ece
74 changed files with 4984 additions and 687 deletions

View File

@@ -19,6 +19,7 @@ import {
ArrowLeft,
RefreshCw,
} from 'lucide-react';
import { useToast } from './ui/Toast';
interface HandTaskPanelProps {
handId: string;
@@ -39,6 +40,7 @@ const RUN_STATUS_CONFIG: Record<string, { label: string; className: string; icon
export function HandTaskPanel({ handId, onBack }: HandTaskPanelProps) {
const { hands, handRuns, loadHands, loadHandRuns, triggerHand, isLoading } = useGatewayStore();
const { toast } = useToast();
const [selectedHand, setSelectedHand] = useState<Hand | null>(null);
const [isActivating, setIsActivating] = useState(false);
const [isRefreshing, setIsRefreshing] = useState(false);
@@ -78,20 +80,49 @@ export function HandTaskPanel({ handId, onBack }: HandTaskPanelProps) {
// Trigger hand execution
const handleActivate = useCallback(async () => {
if (!selectedHand) return;
// Check if hand is already running
if (selectedHand.status === 'running') {
toast(`Hand "${selectedHand.name}" 正在运行中,请等待完成`, 'warning');
return;
}
setIsActivating(true);
console.log(`[HandTaskPanel] Activating hand: ${selectedHand.id} (${selectedHand.name})`);
try {
await triggerHand(selectedHand.id);
// Refresh hands list and task history
await Promise.all([
loadHands(),
loadHandRuns(selectedHand.id, { limit: 50 }),
]);
} catch {
// Error is handled in store
const result = await triggerHand(selectedHand.id);
console.log(`[HandTaskPanel] Activation result:`, result);
if (result) {
toast(`Hand "${selectedHand.name}" 已成功启动`, 'success');
// Refresh hands list and task history
await Promise.all([
loadHands(),
loadHandRuns(selectedHand.id, { limit: 50 }),
]);
} else {
// Check for specific error in store
const storeError = useGatewayStore.getState().error;
if (storeError?.includes('already active')) {
toast(`Hand "${selectedHand.name}" 已在运行中`, 'warning');
} else {
toast(`Hand "${selectedHand.name}" 启动失败: ${storeError || '未知错误'}`, 'error');
}
}
} catch (err) {
const errorMsg = err instanceof Error ? err.message : String(err);
console.error(`[HandTaskPanel] Activation error:`, errorMsg);
if (errorMsg.includes('already active')) {
toast(`Hand "${selectedHand.name}" 已在运行中`, 'warning');
} else {
toast(`Hand "${selectedHand.name}" 启动异常: ${errorMsg}`, 'error');
}
} finally {
setIsActivating(false);
}
}, [selectedHand, triggerHand, loadHands, loadHandRuns]);
}, [selectedHand, triggerHand, loadHands, loadHandRuns, toast]);
if (!selectedHand) {
return (