fix: Neuer Chat Button erstellt Session, Ordner drag&drop im KI-Baum
This commit is contained in:
@@ -43,7 +43,7 @@ function buildTree(folders: ChatFolder[], sessions: ChatSession[]): TreeNode[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function TreeItem({
|
function TreeItem({
|
||||||
node, activeSessionId, onSelectSession, depth, onContextMenu, onDragSession, onDropToFolder, onDelete,
|
node, activeSessionId, onSelectSession, depth, onContextMenu, onDragSession, onDragFolder, onDropToFolder, onDelete,
|
||||||
}: {
|
}: {
|
||||||
node: TreeNode;
|
node: TreeNode;
|
||||||
activeSessionId: string | null;
|
activeSessionId: string | null;
|
||||||
@@ -51,6 +51,7 @@ function TreeItem({
|
|||||||
depth: number;
|
depth: number;
|
||||||
onContextMenu: (e: React.MouseEvent, type: 'session' | 'folder' | 'root', id: string | null) => void;
|
onContextMenu: (e: React.MouseEvent, type: 'session' | 'folder' | 'root', id: string | null) => void;
|
||||||
onDragSession: (sessionId: string) => void;
|
onDragSession: (sessionId: string) => void;
|
||||||
|
onDragFolder: (folderId: string) => void;
|
||||||
onDropToFolder: (folderId: string | null) => void;
|
onDropToFolder: (folderId: string | null) => void;
|
||||||
onDelete: (id: string, type: 'session' | 'folder') => void;
|
onDelete: (id: string, type: 'session' | 'folder') => void;
|
||||||
}) {
|
}) {
|
||||||
@@ -63,7 +64,15 @@ function TreeItem({
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setIsDragOver(false);
|
setIsDragOver(false);
|
||||||
|
const data = e.dataTransfer.getData('text/plain');
|
||||||
|
if (data.startsWith('folder:')) {
|
||||||
|
const draggedFolderId = data.slice(7);
|
||||||
|
if (draggedFolderId !== folderId) {
|
||||||
onDropToFolder(folderId);
|
onDropToFolder(folderId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onDropToFolder(folderId);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDragOver = (e: React.DragEvent) => {
|
const handleDragOver = (e: React.DragEvent) => {
|
||||||
@@ -77,6 +86,12 @@ function TreeItem({
|
|||||||
{/* Folder header - drop target */}
|
{/* Folder header - drop target */}
|
||||||
{!isRoot && (
|
{!isRoot && (
|
||||||
<div
|
<div
|
||||||
|
draggable
|
||||||
|
onDragStart={(e) => {
|
||||||
|
e.dataTransfer.setData('text/plain', `folder:${node.folder!.id}`);
|
||||||
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
|
onDragFolder(node.folder!.id);
|
||||||
|
}}
|
||||||
onDragOver={handleDragOver}
|
onDragOver={handleDragOver}
|
||||||
onDragLeave={() => setIsDragOver(false)}
|
onDragLeave={() => setIsDragOver(false)}
|
||||||
onDrop={handleDrop}
|
onDrop={handleDrop}
|
||||||
@@ -166,6 +181,7 @@ function TreeItem({
|
|||||||
depth={depth + 1}
|
depth={depth + 1}
|
||||||
onContextMenu={onContextMenu}
|
onContextMenu={onContextMenu}
|
||||||
onDragSession={onDragSession}
|
onDragSession={onDragSession}
|
||||||
|
onDragFolder={onDragFolder}
|
||||||
onDropToFolder={onDropToFolder}
|
onDropToFolder={onDropToFolder}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
/>
|
/>
|
||||||
@@ -236,6 +252,7 @@ export function SessionList({ activeSessionId, onSelectSession, isSidebar, class
|
|||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [dragSessionId, setDragSessionId] = useState<string | null>(null);
|
const [dragSessionId, setDragSessionId] = useState<string | null>(null);
|
||||||
|
const [dragFolderId, setDragFolderId] = useState<string | null>(null);
|
||||||
const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);
|
const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);
|
||||||
|
|
||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
@@ -296,6 +313,14 @@ export function SessionList({ activeSessionId, onSelectSession, isSidebar, class
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDropToFolder = async (folderId: string | null) => {
|
const handleDropToFolder = async (folderId: string | null) => {
|
||||||
|
if (dragFolderId) {
|
||||||
|
try {
|
||||||
|
await updateFolder(dragFolderId, { parent_id: folderId });
|
||||||
|
setDragFolderId(null);
|
||||||
|
loadData();
|
||||||
|
} catch (e) { setError(e instanceof Error ? e.message : 'Failed to move folder'); }
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!dragSessionId) return;
|
if (!dragSessionId) return;
|
||||||
try {
|
try {
|
||||||
await updateSession(dragSessionId, { folder_id: folderId });
|
await updateSession(dragSessionId, { folder_id: folderId });
|
||||||
@@ -326,6 +351,7 @@ export function SessionList({ activeSessionId, onSelectSession, isSidebar, class
|
|||||||
depth={0}
|
depth={0}
|
||||||
onContextMenu={handleContextMenu}
|
onContextMenu={handleContextMenu}
|
||||||
onDragSession={setDragSessionId}
|
onDragSession={setDragSessionId}
|
||||||
|
onDragFolder={setDragFolderId}
|
||||||
onDropToFolder={handleDropToFolder}
|
onDropToFolder={handleDropToFolder}
|
||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { SessionList } from '@/components/ai/SessionList';
|
|||||||
import { ChatWindow } from '@/components/ai/ChatWindow';
|
import { ChatWindow } from '@/components/ai/ChatWindow';
|
||||||
import { ResizablePanel } from '@/components/ui/ResizablePanel';
|
import { ResizablePanel } from '@/components/ui/ResizablePanel';
|
||||||
import { usePluginToolbarStore } from '@/store/pluginToolbarStore';
|
import { usePluginToolbarStore } from '@/store/pluginToolbarStore';
|
||||||
import { fetchAgents, type AIAgent } from '@/api/ai';
|
import { fetchAgents, createSession, type AIAgent } from '@/api/ai';
|
||||||
|
|
||||||
export function AIAssistantPage() {
|
export function AIAssistantPage() {
|
||||||
const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
|
const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
|
||||||
@@ -39,7 +39,16 @@ export function AIAssistantPage() {
|
|||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
|
||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
onClick: () => { setActiveSessionId(null); setMobileView('list'); setRefreshKey(k => k + 1); },
|
onClick: async () => {
|
||||||
|
try {
|
||||||
|
const session = await createSession({ is_sidebar: false });
|
||||||
|
setActiveSessionId(session.id);
|
||||||
|
setMobileView('chat');
|
||||||
|
setRefreshKey(k => k + 1);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to create session:', e);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'new-folder',
|
id: 'new-folder',
|
||||||
|
|||||||
Reference in New Issue
Block a user