feat: v0.1.1 迭代——人设外键重构、Chat UI优化、意识节点防幻觉、日志双视图
1. 人设外键重构:persona_template 成为 system_prompt 唯一权威来源, agent/系统节点通过 persona_id FK 引用,含数据迁移脚本 2. Chat UI:去掉底部AI提示、加号改为弹出菜单、新建对话乐观跳转 3. 意识节点:无可用worker时禁止编造agent_id,只能自行完成或拒绝 4. 日志页面:双tab布局(系统日志 + 工作流日志列表选择) 5. 其他:SSE流式聊天、对话删除/重命名、standalone模式修复 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Plus, Trash2, MessageSquare, Workflow as WorkflowIcon } from 'lucide-react';
|
||||
import { Plus, Trash2, MessageSquare, Workflow as WorkflowIcon, Pencil, Check } from 'lucide-react';
|
||||
import apiClient from '../../api/client';
|
||||
import type { Workflow } from '../../types';
|
||||
import { useChatStore } from '../../store/useChatStore';
|
||||
@@ -13,15 +13,17 @@ export function LeftPanel({ activeTab }: LeftPanelProps) {
|
||||
const { t } = useTranslation();
|
||||
const [workflows, setWorkflows] = useState<Workflow[]>([]);
|
||||
const [loadingWorkflows, setLoadingWorkflows] = useState(false);
|
||||
const [renamingId, setRenamingId] = useState<string | null>(null);
|
||||
const [renameValue, setRenameValue] = useState('');
|
||||
|
||||
const {
|
||||
sessions,
|
||||
activeSessionId,
|
||||
setActiveSessionId,
|
||||
removeSession,
|
||||
createChat,
|
||||
selectedWorkflow,
|
||||
setSelectedWorkflow,
|
||||
updateSessionTitle,
|
||||
} = useChatStore();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -57,8 +59,8 @@ export function LeftPanel({ activeTab }: LeftPanelProps) {
|
||||
};
|
||||
}, [activeTab]);
|
||||
|
||||
const handleNewChat = async () => {
|
||||
await createChat(t('chat.newChat'), '你好');
|
||||
const handleNewChat = () => {
|
||||
setActiveSessionId(null);
|
||||
};
|
||||
|
||||
const handleDeleteChat = (e: React.MouseEvent, id: string) => {
|
||||
@@ -66,6 +68,20 @@ export function LeftPanel({ activeTab }: LeftPanelProps) {
|
||||
removeSession(id);
|
||||
};
|
||||
|
||||
const handleStartRename = (e: React.MouseEvent, id: string, title: string) => {
|
||||
e.stopPropagation();
|
||||
setRenamingId(id);
|
||||
setRenameValue(title);
|
||||
};
|
||||
|
||||
const handleConfirmRename = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
if (renamingId && renameValue.trim()) {
|
||||
updateSessionTitle(renamingId, renameValue.trim());
|
||||
}
|
||||
setRenamingId(null);
|
||||
};
|
||||
|
||||
const isChats = activeTab === 'chats';
|
||||
|
||||
return (
|
||||
@@ -95,6 +111,7 @@ export function LeftPanel({ activeTab }: LeftPanelProps) {
|
||||
) : (
|
||||
sessions.map((session) => {
|
||||
const isActive = activeSessionId === session.id;
|
||||
const isRenaming = renamingId === session.id;
|
||||
return (
|
||||
<div
|
||||
key={session.id}
|
||||
@@ -109,16 +126,35 @@ export function LeftPanel({ activeTab }: LeftPanelProps) {
|
||||
<MessageSquare size={12} className={isActive ? 'text-accent' : 'text-text-muted'} />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className={`text-xs truncate ${isActive ? 'text-text-primary font-medium' : 'text-text-secondary'}`}>
|
||||
{session.title}
|
||||
</h3>
|
||||
{isRenaming ? (
|
||||
<input
|
||||
autoFocus
|
||||
value={renameValue}
|
||||
onChange={(e) => setRenameValue(e.target.value)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => { if (e.key === 'Enter') handleConfirmRename(e as any); if (e.key === 'Escape') setRenamingId(null); }}
|
||||
className="w-full text-xs bg-bg-input border border-border-primary rounded px-1.5 py-0.5 text-text-primary focus:outline-none focus:border-accent"
|
||||
/>
|
||||
) : (
|
||||
<h3 className={`text-xs truncate ${isActive ? 'text-text-primary font-medium' : 'text-text-secondary'}`}>
|
||||
{session.title}
|
||||
</h3>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
onClick={(e) => handleDeleteChat(e, session.id)}
|
||||
className="opacity-0 group-hover:opacity-100 p-1 rounded text-text-muted hover:text-danger transition-all"
|
||||
>
|
||||
<Trash2 size={11} />
|
||||
</button>
|
||||
{isRenaming ? (
|
||||
<button onClick={handleConfirmRename} className="p-1 rounded text-accent hover:bg-accent-light transition-all">
|
||||
<Check size={11} />
|
||||
</button>
|
||||
) : (
|
||||
<div className="flex items-center opacity-0 group-hover:opacity-100 transition-all">
|
||||
<button onClick={(e) => handleStartRename(e, session.id, session.title)} className="p-1 rounded text-text-muted hover:text-accent transition-all">
|
||||
<Pencil size={11} />
|
||||
</button>
|
||||
<button onClick={(e) => handleDeleteChat(e, session.id)} className="p-1 rounded text-text-muted hover:text-danger transition-all">
|
||||
<Trash2 size={11} />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user