[moz] feat(frontend): 工具链面板加 from/to 显示 + 筛选 + 修复事件类型未知
CI / lint (pull_request) Successful in 7s
CI / test (pull_request) Successful in 29s
CI / frontend (pull_request) Successful in 11s
CI / notify-on-failure (pull_request) Successful in 0s

- 前端:列表项加 from → to 标签(Agent 中文名)
- 前端:加「全部 / 未处理」筛选按钮
- 前端:详情区也显示 from → to
- 后端:ToolchainContextSection 修复事件类型 fallback 为中文标签
- 后端:加来源/指派信息到 prompt 消息体
This commit is contained in:
cfdaily
2026-06-14 17:12:11 +08:00
parent 65910f5417
commit 91685ebfdd
2 changed files with 72 additions and 3 deletions
+47 -2
View File
@@ -4,6 +4,28 @@
*/
import { useEffect, useState } from 'react';
const AGENT_NAMES: Record<string, string> = {
'pangtong-fujunshi': '庞统',
'simayi-challenger': '司马懿',
'zhangfei-dev': '张飞',
'guanyu-dev': '关羽',
'zhaoyun-data': '赵云',
'jiangwei-infra': '姜维',
'system': '系统',
};
const EVENT_LABELS: Record<string, string> = {
'review_request': 'Review 请求',
'review_result': 'Review 结果',
'review_merged': 'PR 合并',
'review_comment': 'Review 评论',
'review_updated': 'Review 更新',
'ci_failure': 'CI 失败',
'deploy_failure': '部署失败',
'issue_assigned': 'Issue 指派',
'mention': '@提及',
};
const STATUS_COLORS: Record<string, string> = {
pending: '#f59e0b22', claimed: '#6a9eff22', working: '#6a9eff22',
review: '#818cf822', done: '#2ecc8a22', failed: '#ef444422',
@@ -36,6 +58,7 @@ export default function ToolchainPanel() {
const [detail, setDetail] = useState<any>(null);
const [searchQuery, setSearchQuery] = useState('');
const [loading, setLoading] = useState(false);
const [filterMode, setFilterMode] = useState<'all' | 'pending'>('all');
const loadTasks = async (q?: string) => {
setLoading(true);
@@ -52,6 +75,10 @@ export default function ToolchainPanel() {
setLoading(false);
};
const displayed = filterMode === 'pending'
? tasks.filter(t => !['done', 'failed', 'cancelled'].includes(t.status))
: tasks;
useEffect(() => { loadTasks(); }, []);
// 搜索防抖 300ms
@@ -120,7 +147,19 @@ export default function ToolchainPanel() {
padding: '3px 8px', borderRadius: 4, fontSize: 10,
border: '1px solid #2a3550', background: '#161b2e', color: '#8899aa', cursor: 'pointer',
}}>🔄</button>
<span style={{ fontSize: 10, color: 'var(--muted)' }}>{tasks.length} </span>
<button onClick={() => setFilterMode('all')} style={{
padding: '3px 8px', borderRadius: 4, fontSize: 10,
border: `1px solid ${filterMode === 'all' ? 'var(--acc)' : '#2a3550'}`,
background: filterMode === 'all' ? 'var(--acc)22' : '#161b2e',
color: filterMode === 'all' ? 'var(--acc)' : '#8899aa', cursor: 'pointer',
}}></button>
<button onClick={() => setFilterMode('pending')} style={{
padding: '3px 8px', borderRadius: 4, fontSize: 10,
border: `1px solid ${filterMode === 'pending' ? 'var(--acc)' : '#2a3550'}`,
background: filterMode === 'pending' ? 'var(--acc)22' : '#161b2e',
color: filterMode === 'pending' ? 'var(--acc)' : '#8899aa', cursor: 'pointer',
}}></button>
<span style={{ fontSize: 10, color: 'var(--muted)' }}>{filterMode === 'pending' ? displayed.length : tasks.length} </span>
</div>
{/* 事件列表 */}
@@ -130,7 +169,7 @@ export default function ToolchainPanel() {
{loading ? '加载中...' : '暂无工具链事件'}
</div>
)}
{tasks.map((t: any) => (
{displayed.map((t: any) => (
<div key={t.id} onClick={() => setSelectedId(t.id)} style={{
padding: '10px 14px', borderBottom: '1px solid var(--line)',
cursor: 'pointer', transition: 'background .15s',
@@ -151,6 +190,9 @@ export default function ToolchainPanel() {
fontSize: 12, fontWeight: 500, color: '#dde4f8',
overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
}}>{t.title}</div>
<div style={{ fontSize: 10, color: 'var(--muted)', marginTop: 2 }}>
{AGENT_NAMES['system'] || '系统'} {AGENT_NAMES[t.assignee] || t.assignee || '?'}
</div>
</div>
))}
</div>
@@ -174,6 +216,9 @@ export default function ToolchainPanel() {
<span style={{ fontSize: 10, color: 'var(--muted)' }}>{detail.id}</span>
</div>
<div style={{ fontSize: 18, fontWeight: 700, lineHeight: 1.3 }}>{detail.title}</div>
<div style={{ fontSize: 11, color: 'var(--muted)', marginTop: 4 }}>
{AGENT_NAMES['system'] || '系统'} {AGENT_NAMES[detail.assignee] || detail.assignee || '?'}
</div>
<div style={{ fontSize: 12, color: 'var(--muted)', marginTop: 6 }}>
{fmtTime(detail.created_at)}
</div>