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

@@ -158,7 +158,7 @@ export function MemoryGraph({ className = '' }: MemoryGraphProps) {
const [searchQuery, setSearchQuery] = useState('');
const { currentAgent } = useChatStore();
const agentId = currentAgent?.id || 'default';
const agentId = currentAgent?.id || 'zclaw-main';
const {
isLoading,
@@ -225,8 +225,8 @@ export function MemoryGraph({ className = '' }: MemoryGraphProps) {
canvas.height = layout.height * dpr;
ctx.scale(dpr, dpr);
// 清空画布
ctx.fillStyle = '#1a1a2e';
// 清空画布 - 使用浅色背景匹配系统主题
ctx.fillStyle = '#f9fafb'; // gray-50
ctx.fillRect(0, 0, layout.width, layout.height);
// 应用变换
@@ -299,7 +299,7 @@ export function MemoryGraph({ className = '' }: MemoryGraphProps) {
ctx.arc(legendX, legendY, 6, 0, Math.PI * 2);
ctx.fillStyle = colors.fill;
ctx.fill();
ctx.fillStyle = '#9ca3af';
ctx.fillStyle = '#6b7280'; // gray-500 for better visibility on light background
ctx.textAlign = 'left';
ctx.fillText(label, legendX + 12, legendY + 4);
legendX += 70;
@@ -377,7 +377,7 @@ export function MemoryGraph({ className = '' }: MemoryGraphProps) {
return (
<div className={`flex flex-col h-full ${className}`}>
{/* 工具栏 */}
<div className="flex items-center gap-2 p-2 bg-gray-800/50 rounded-t-lg border-b border-gray-700">
<div className="flex items-center gap-2 p-2 bg-gray-100 dark:bg-gray-800/50 rounded-t-lg border-b border-gray-200 dark:border-gray-700">
{/* 搜索框 */}
<div className="relative flex-1 max-w-xs">
<Search className="absolute left-2 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
@@ -386,7 +386,7 @@ export function MemoryGraph({ className = '' }: MemoryGraphProps) {
placeholder="搜索记忆..."
value={searchQuery}
onChange={(e) => handleSearch(e.target.value)}
className="w-full pl-8 pr-2 py-1 bg-gray-900 border border-gray-700 rounded text-sm text-white placeholder-gray-500 focus:outline-none focus:border-blue-500"
className="w-full pl-8 pr-2 py-1 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded text-sm text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:border-orange-400 dark:focus:border-blue-500"
/>
</div>
@@ -459,7 +459,7 @@ export function MemoryGraph({ className = '' }: MemoryGraphProps) {
initial={{ height: 0, opacity: 0 }}
animate={{ height: 'auto', opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
className="overflow-hidden bg-gray-800/30 border-b border-gray-700"
className="overflow-hidden bg-gray-50 dark:bg-gray-800/30 border-b border-gray-200 dark:border-gray-700"
>
<div className="p-3 flex flex-wrap gap-3">
{/* 类型筛选 */}
@@ -476,8 +476,8 @@ export function MemoryGraph({ className = '' }: MemoryGraphProps) {
}}
className={`px-2 py-1 text-xs rounded ${
filter.types.includes(type)
? 'bg-blue-600 text-white'
: 'bg-gray-700 text-gray-300'
? 'bg-orange-500 text-white'
: 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300'
}`}
>
{TYPE_LABELS[type]}
@@ -510,9 +510,9 @@ export function MemoryGraph({ className = '' }: MemoryGraphProps) {
</AnimatePresence>
{/* 图谱画布 */}
<div className="flex-1 relative overflow-hidden bg-gray-900">
<div className="flex-1 relative overflow-hidden bg-gray-50 dark:bg-gray-900">
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center bg-gray-900/80 z-10">
<div className="absolute inset-0 flex items-center justify-center bg-gray-50/80 dark:bg-gray-900/80 z-10">
<RefreshCw className="w-8 h-8 text-blue-500 animate-spin" />
</div>
)}
@@ -541,7 +541,7 @@ export function MemoryGraph({ className = '' }: MemoryGraphProps) {
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 20 }}
className="absolute top-4 right-4 w-64 bg-gray-800 rounded-lg border border-gray-700 p-4 shadow-xl"
className="absolute top-4 right-4 w-64 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-4 shadow-xl"
>
<div className="flex items-center justify-between mb-3">
<Badge variant={selectedNode.type as any}>
@@ -549,7 +549,7 @@ export function MemoryGraph({ className = '' }: MemoryGraphProps) {
</Badge>
<button
onClick={() => selectNode(null)}
className="text-gray-400 hover:text-white"
className="text-gray-400 hover:text-gray-600 dark:hover:text-white"
>
<X className="w-4 h-4" />
</button>
@@ -557,7 +557,7 @@ export function MemoryGraph({ className = '' }: MemoryGraphProps) {
<p className="text-sm text-gray-200 mb-3">{selectedNode.label}</p>
<div className="space-y-2 text-xs text-gray-400">
<div className="space-y-2 text-xs text-gray-500 dark:text-gray-400">
<div className="flex items-center gap-2">
<Star className="w-3 h-3" />
: {selectedNode.importance}
@@ -573,9 +573,9 @@ export function MemoryGraph({ className = '' }: MemoryGraphProps) {
</div>
{/* 关联边统计 */}
<div className="mt-3 pt-3 border-t border-gray-700">
<div className="text-xs text-gray-400 mb-1">:</div>
<div className="text-sm text-gray-200">
<div className="mt-3 pt-3 border-t border-gray-200 dark:border-gray-700">
<div className="text-xs text-gray-500 dark:text-gray-400 mb-1">:</div>
<div className="text-sm text-gray-700 dark:text-gray-200">
{filteredEdges.filter(
e => e.source === selectedNode.id || e.target === selectedNode.id
).length}
@@ -598,7 +598,7 @@ export function MemoryGraph({ className = '' }: MemoryGraphProps) {
</div>
{/* 状态栏 */}
<div className="flex items-center justify-between px-3 py-1 bg-gray-800/50 rounded-b-lg text-xs text-gray-400">
<div className="flex items-center justify-between px-3 py-1 bg-gray-100 dark:bg-gray-800/50 rounded-b-lg text-xs text-gray-500 dark:text-gray-400">
<div className="flex items-center gap-4">
<span>: {filteredNodes.length}</span>
<span>: {filteredEdges.length}</span>