feat: M4-07 — Hermes agent tasks + artifacts tabs with approval buttons
All checks were successful
Deploy Admin Frontend / build-and-deploy (push) Successful in 9s
All checks were successful
Deploy Admin Frontend / build-and-deploy (push) Successful in 9s
- Replace iframe-only HermesSettings with 3-tab page - Agent tasks table with approve/reject buttons - Agent artifacts table with type labels - Keep Hermes panel iframe tab Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
cb83928d7a
commit
8b6c957a30
@ -1,11 +1,85 @@
|
||||
import { Tabs, Table, Tag, Button, Space, Typography } from 'antd'
|
||||
import { CheckOutlined, CloseOutlined, RobotOutlined } from '@ant-design/icons'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { api } from '@/services/http-client'
|
||||
import { message } from 'antd'
|
||||
|
||||
const { Title } = Typography
|
||||
|
||||
const statusColors: Record<string, string> = { pending: 'blue', approved: 'green', rejected: 'red', completed: 'green' }
|
||||
const artifactTypeLabels: Record<string, string> = { issue_draft: 'Issue 草稿', milestone_summary: '里程碑总结', release_notes: '发布说明', decision_record: '决策记录' }
|
||||
|
||||
export default function HermesSettings() {
|
||||
const qc = useQueryClient()
|
||||
|
||||
const { data: tasks, isLoading: tLoading } = useQuery({
|
||||
queryKey: ['hermes', 'tasks'],
|
||||
queryFn: () => api.get<any[]>('/admin-api/hermes/tasks').then(d => d ?? []),
|
||||
})
|
||||
|
||||
const { data: artifacts, isLoading: aLoading } = useQuery({
|
||||
queryKey: ['hermes', 'artifacts'],
|
||||
queryFn: () => api.get<any[]>('/admin-api/hermes/artifacts').then(d => d ?? []),
|
||||
})
|
||||
|
||||
const approveTask = useMutation({
|
||||
mutationFn: (id: string) => api.post(`/admin-api/hermes/tasks/${id}/approve`),
|
||||
onSuccess: () => { message.success('已通过'); qc.invalidateQueries({ queryKey: ['hermes', 'tasks'] }) },
|
||||
})
|
||||
|
||||
const rejectTask = useMutation({
|
||||
mutationFn: (id: string) => api.post(`/admin-api/hermes/tasks/${id}/reject`),
|
||||
onSuccess: () => { message.success('已驳回'); qc.invalidateQueries({ queryKey: ['hermes', 'tasks'] }) },
|
||||
})
|
||||
|
||||
const taskColumns = [
|
||||
{ title: 'ID', dataIndex: 'id', width: 80, ellipsis: true },
|
||||
{ title: '类型', dataIndex: 'type', width: 90 },
|
||||
{ title: '输入', dataIndex: 'input', width: 180, ellipsis: true, render: (i: string) => i ? i.slice(0, 100) : '-' },
|
||||
{ title: '输出', dataIndex: 'output', width: 200, ellipsis: true, render: (o: string) => o ? o.slice(0, 120) : '-' },
|
||||
{ title: '状态', dataIndex: 'status', width: 70, render: (s: string) => <Tag color={statusColors[s] || 'default'}>{s}</Tag> },
|
||||
{ title: '创建时间', dataIndex: 'createdAt', width: 110, render: (d: string) => new Date(d).toLocaleString() },
|
||||
{
|
||||
title: '操作', width: 120,
|
||||
render: (_: any, r: any) => r.status === 'pending' ? (
|
||||
<Space>
|
||||
<Button size="small" type="primary" icon={<CheckOutlined />} onClick={() => approveTask.mutate(r.id)}>通过</Button>
|
||||
<Button size="small" danger icon={<CloseOutlined />} onClick={() => rejectTask.mutate(r.id)}>驳回</Button>
|
||||
</Space>
|
||||
) : null,
|
||||
},
|
||||
]
|
||||
|
||||
const artifactColumns = [
|
||||
{ title: 'ID', dataIndex: 'id', width: 80, ellipsis: true },
|
||||
{ title: '类型', dataIndex: 'type', width: 100, render: (t: string) => artifactTypeLabels[t] || t },
|
||||
{ title: '标题', dataIndex: 'title', width: 200, ellipsis: true },
|
||||
{ title: '内容', dataIndex: 'content', width: 250, ellipsis: true, render: (c: string) => c ? c.slice(0, 150) : '-' },
|
||||
{ title: '状态', dataIndex: 'status', width: 70, render: (s: string) => <Tag color={s === 'draft' ? 'orange' : 'green'}>{s}</Tag> },
|
||||
{ title: '创建时间', dataIndex: 'createdAt', width: 110, render: (d: string) => new Date(d).toLocaleString() },
|
||||
]
|
||||
|
||||
return (
|
||||
<div style={{ width: '100%', height: 'calc(100vh - 112px)', overflow: 'hidden' }}>
|
||||
<iframe
|
||||
src="https://hermes.admin.longde.cloud"
|
||||
style={{ width: '100%', height: '100%', border: 'none' }}
|
||||
title="Hermes Agent"
|
||||
/>
|
||||
<div>
|
||||
<Title level={4}><RobotOutlined /> Hermes Agent</Title>
|
||||
<Tabs defaultActiveKey="tasks" items={[
|
||||
{
|
||||
key: 'tasks', label: 'Agent 任务',
|
||||
children: <Table dataSource={tasks || []} columns={taskColumns} rowKey="id" loading={tLoading} size="small" scroll={{ x: 950 }} />,
|
||||
},
|
||||
{
|
||||
key: 'artifacts', label: '产出物',
|
||||
children: <Table dataSource={artifacts || []} columns={artifactColumns} rowKey="id" loading={aLoading} size="small" scroll={{ x: 900 }} />,
|
||||
},
|
||||
{
|
||||
key: 'chat', label: 'Hermes 面板',
|
||||
children: (
|
||||
<div style={{ width: '100%', height: 'calc(100vh - 200px)' }}>
|
||||
<iframe src="https://hermes.admin.longde.cloud" style={{ width: '100%', height: '100%', border: 'none' }} title="Hermes Agent" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user