From e8ac10288f0efd4910ead489f2642132db1ae8f4 Mon Sep 17 00:00:00 2001 From: taohe Date: Sat, 13 Jun 2026 12:00:47 +0800 Subject: [PATCH] Polish skills tab UI --- taskboard-electron/src/renderer/App.tsx | 439 +++++++++++++++--------- 1 file changed, 285 insertions(+), 154 deletions(-) diff --git a/taskboard-electron/src/renderer/App.tsx b/taskboard-electron/src/renderer/App.tsx index d306a8b..950948f 100644 --- a/taskboard-electron/src/renderer/App.tsx +++ b/taskboard-electron/src/renderer/App.tsx @@ -8,6 +8,7 @@ import { Moon, Play, Plus, + Radar, Search, Settings, Sparkles, @@ -177,7 +178,7 @@ const DEFAULT_TIMEOUT_SECONDS = 12000; function FormattedOutput({ content, theme }) { if (!content) return null; - // 解析JSON流数据,只显示关键信息 + // Parse the JSON stream and render only the useful signal. const parseStreamJSON = (text) => { const lines = text.split("\n"); const parsedLines = []; @@ -325,7 +326,7 @@ function FormattedOutput({ content, theme }) { } case "result": - // 最终结果 + // Final result. if (event.result) { parsedLines.push({ type: "result", @@ -336,7 +337,7 @@ function FormattedOutput({ content, theme }) { break; case "error": - // 错误信息 + // Error details. parsedLines.push({ type: "error", text: `❌ Error: ${event.error || "Unknown error"}`, @@ -345,10 +346,10 @@ function FormattedOutput({ content, theme }) { break; default: - // 其他事件类型 - 显示更多信息 + // Other event types: surface compact context. if (eventType) { let displayText = `[${eventType}]`; - // 尝试显示事件中的关键信息 + // Try to render the key event fields. if (event.message) { const msg = event.message; if (msg.content && Array.isArray(msg.content)) { @@ -377,9 +378,9 @@ function FormattedOutput({ content, theme }) { } } } catch (_error) { - // 如果不是有效的JSON,可能是普通文本输出 + // If it is not valid JSON, it may be plain text output. if (line.trim() && !line.startsWith("{")) { - // 只显示有意义的非JSON行 + // Only render meaningful non-JSON lines. if (line.includes("error") || line.includes("Error")) { parsedLines.push({ type: "error", @@ -393,7 +394,7 @@ function FormattedOutput({ content, theme }) { style: { color: theme.green }, }); } else if (line.length > 10) { - // 只显示较长的非JSON行 + // Only render longer non-JSON lines. parsedLines.push({ type: "text", text: line, @@ -3116,7 +3117,7 @@ function DetailPanel({ task, onClose, onResume }: any) { if (res.ok && !cancelled) { const data = await res.json(); const currentOutput = data.output || ""; - // 增量更新:只添加新内容 + // Incremental update: append only new output. if (currentOutput.length > lastOutputLength) { const newContent = currentOutput.slice(lastOutputLength); setLiveOutput((prev) => prev + newContent); @@ -3126,7 +3127,7 @@ function DetailPanel({ task, onClose, onResume }: any) { } catch {} }; poll(); - const interval = setInterval(poll, 1000); // 缩短轮询间隔到1秒 + const interval = setInterval(poll, 1000); return () => { cancelled = true; clearInterval(interval); @@ -3397,7 +3398,7 @@ function DetailPanel({ task, onClose, onResume }: any) { overflow: "hidden", }} > - {/* 工具栏 */} + {/* Toolbar */}
- {/* 输出内容区域 */} + {/* Output content */} {showLiveOutput && (
- ✨ 已发送!任务正在重新唤醒,请稍候~ + Sent. The task is waking up again.
)} @@ -5346,19 +5363,21 @@ function SkillPatternCard({ p, tasks, onDraft, onApprove, onDismiss }) { }} >
- 首次 + First seen {(p.first_seen || "").replace("T", " ").slice(0, 19) || "—"} -  最近 + · Last seen {(p.last_seen || "").replace("T", " ").slice(0, 19) || "—"}
-
贡献的任务({taskCount}):
+
+ Contributing tasks ({taskCount}): +
{taskIds.length === 0 && } {taskIds.map((tid) => { const t = (tasks || []).find((x) => x.id === tid); return ( - #{tid} {t ? t.title : (已删除)} + #{tid} {t ? t.title : (deleted)} ); })} @@ -5378,13 +5397,15 @@ function SkillPatternCard({ p, tasks, onDraft, onApprove, onDismiss }) { border: `1px solid ${p.draft_worthy ? "rgba(34,197,94,0.3)" : "rgba(245,158,11,0.35)"}`, }} > - {p.draft_worthy ? "✓ agent 建议沉淀" : "⚠ agent 认为价值有限(可仍批准或驳回)"} - {p.draft_worthiness_reason ? `:${p.draft_worthiness_reason}` : ""} + {p.draft_worthy + ? "Agent recommends turning this into a skill" + : "Agent thinks this may have limited value. You can still approve or reject it."} + {p.draft_worthiness_reason ? `: ${p.draft_worthiness_reason}` : ""}
)} {p.status === "promoted" && ( -
✓ 已沉淀为 Skill
+
Promoted to Skill
)} {(p.status === "candidate" || p.status === "tracking") && @@ -5392,24 +5413,26 @@ function SkillPatternCard({ p, tasks, onDraft, onApprove, onDismiss }) { draftStatus !== "drafting" && (
{p.status === "tracking" && ( - 未达自动阈值,可手动蒸馏(agent 会判断是否值得) + Below the automatic threshold. You can still distill it manually. )} {draftStatus === "error" && ( - 蒸馏失败:{p.draft_error} + + Distill failed: {p.draft_error} + )}
)} {draftStatus === "drafting" && ( -
蒸馏中…
+
Distilling…
)} {draftStatus === "ready" && @@ -5430,7 +5453,7 @@ function SkillPatternCard({ p, tasks, onDraft, onApprove, onDismiss }) { borderRadius: 6, }} > - {fm.name || "(无 name)"} + {fm.name || "(no name)"} → ~/.claude/skills/{fm.name || "…"}/SKILL.md @@ -5452,7 +5475,7 @@ function SkillPatternCard({ p, tasks, onDraft, onApprove, onDismiss }) { letterSpacing: 0.3, }} > - SKILL.md · 可编辑(frontmatter 决定名称与触发描述) + SKILL.md · editable. Frontmatter controls the name and trigger description.