Files
makelore/src/pages/CloudAgents/CloudOverview.tsx

67 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useEffect, useRef, useState } from 'react';
import { Button } from '@/components/ui/button';
import { cloudAgentsApi } from '@/lib/cloud-agents-api';
import type { CloudAgentEntry, CloudThread } from '../../../shared/cloud-agents';
import { cloudStatus } from './CloudChat';
export function CloudOverview({ section, onAgent, onThread }: {
section: 'received' | 'activity'; onAgent: (entry: CloudAgentEntry) => void; onThread: (thread: CloudThread) => void;
}) {
const [agents, setAgents] = useState<CloudAgentEntry[]>([]);
const [threads, setThreads] = useState<CloudThread[]>([]);
const [error, setError] = useState('');
const [loading, setLoading] = useState(true);
const [offset, setOffset] = useState<number | null>(null);
const [refresh, setRefresh] = useState(0);
const paged = useRef(false);
useEffect(() => {
let live = true;
paged.current = false;
setLoading(true);
const load = async () => {
try {
if (section === 'received') {
const result = await cloudAgentsApi.call('received', {});
if (live) setAgents(result.agents);
} else {
const result = await cloudAgentsApi.call('threads', {});
if (live) { setThreads(result.threads); setOffset(result.next_offset); }
}
if (live) setError('');
} catch(e) { if (live) setError(e instanceof Error ? e.message : '暂时无法读取'); }
finally { if (live) setLoading(false); }
};
void load();
const timer = window.setInterval(() => { if (!paged.current) void load(); }, 15000);
return () => { live = false; window.clearInterval(timer); };
}, [section, refresh]);
const more = async () => {
if (offset === null) return;
paged.current = true;
setLoading(true);
try { const page = await cloudAgentsApi.call('threads', { offset }); setThreads(v => [...v, ...page.threads]); setOffset(page.next_offset); }
catch(e) { setError(e instanceof Error ? e.message : '加载失败'); } finally { setLoading(false); }
};
return <section className="space-y-4">
{error && <p role="alert" className="text-sm text-destructive">{error}<Button variant="ghost" onClick={() => setRefresh(v => v + 1)}>重新连接</Button></p>}
{section === 'received' ? <>
<p className="text-sm text-muted-foreground">这里显示其他创作者授权你使用的智能体。由创建者承担费用,你的会话和文件仅属于你。</p>
{!loading && !agents.length && <p className="py-12 text-center text-sm text-muted-foreground">还没有收到分享</p>}
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">{agents.map(agent => <button key={agent.slug} onClick={() => onAgent(agent)}
className="rounded-xl border border-border p-5 text-left transition-colors hover:bg-muted/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring">
<h2 className="font-medium">{agent.name}</h2><p className="mt-2 line-clamp-3 text-sm leading-6 text-muted-foreground">{agent.purpose}</p>
<p className="mt-4 text-xs text-muted-foreground">版本 {agent.published_version} · 打开对话</p>
</button>)}</div></> : <>
<p className="text-sm text-muted-foreground">查看自己的对话、自动任务结果和待确认事项。</p>
{!loading && !threads.length && <p className="py-12 text-center text-sm text-muted-foreground">还没有运行记录</p>}
{threads.map(thread => <button key={thread.thread_id} onClick={() => onThread(thread)}
className="flex min-h-20 w-full items-center justify-between gap-4 rounded-xl border border-border p-4 text-left transition-colors hover:bg-muted/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring">
<div className="min-w-0"><h2 className="truncate text-sm font-medium">{thread.unread && <span className="mr-2 inline-block h-2 w-2 rounded-full bg-violet-500" aria-label="未读" />}{thread.title || '未命名对话'}</h2>
<p className="mt-2 text-xs text-muted-foreground">{thread.mode === 'preview' ? '草稿预览' : '正式运行'} · {new Date(thread.updated_at).toLocaleString()}</p></div>
<span className="shrink-0 text-sm text-muted-foreground">{cloudStatus(thread.status)}</span>
</button>)}
{offset !== null && <Button variant="outline" disabled={loading} onClick={() => void more()}>加载更早记录</Button>}
</>}
</section>;
}