From d9b17431a799a0354103ef390f6db15f34fb92be Mon Sep 17 00:00:00 2001
From: blackhao <13851610112@163.com>
Date: Wed, 10 Dec 2025 19:30:26 -0600
Subject: init file sys

---
 frontend/src/components/LeftSidebar.tsx | 58 ++++++++++++++++++++++++++++++---
 1 file changed, 54 insertions(+), 4 deletions(-)

(limited to 'frontend/src/components/LeftSidebar.tsx')

diff --git a/frontend/src/components/LeftSidebar.tsx b/frontend/src/components/LeftSidebar.tsx
index a75df39..aff2df8 100644
--- a/frontend/src/components/LeftSidebar.tsx
+++ b/frontend/src/components/LeftSidebar.tsx
@@ -2,7 +2,7 @@ import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react'
 import { useReactFlow } from 'reactflow';
 import { 
   Folder, FileText, Archive, ChevronLeft, ChevronRight, Trash2, MessageSquare, 
-  MoreVertical, Download, Upload, Plus, RefreshCw, Edit3 
+  MoreVertical, Download, Upload, Plus, RefreshCw, Edit3, Loader2
 } from 'lucide-react';
 import useFlowStore, { type FSItem, type BlueprintDocument, type FileMeta } from '../store/flowStore';
 
@@ -19,6 +19,7 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
     createNodeFromArchive,
     theme,
     files,
+    uploadingFileIds,
     projectTree,
     currentBlueprintPath,
     saveStatus,
@@ -47,6 +48,9 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
   const [dragItem, setDragItem] = useState<FSItem | null>(null);
   const [showSaveStatus, setShowSaveStatus] = useState(false);
   const [expanded, setExpanded] = useState<Set<string>>(() => new Set(['.']));
+  const [fileProvider, setFileProvider] = useState<'local' | 'openai' | 'google'>('local');
+  const [openaiPurpose, setOpenaiPurpose] = useState<string>('user_data');
+  const [fileSearch, setFileSearch] = useState('');
   
   const handleDragStart = (e: React.DragEvent, archiveId: string) => {
     e.dataTransfer.setData('archiveId', archiveId);
@@ -235,7 +239,10 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
     let failed: string[] = [];
     for (const f of Array.from(list)) {
       try {
-        await uploadFile(f);
+        await uploadFile(f, {
+          provider: fileProvider,
+          purpose: fileProvider === 'openai' ? openaiPurpose : undefined,
+        });
         ok += 1;
       } catch (e) {
         console.error(e);
@@ -251,6 +258,13 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
     }
   };
 
+  const filteredFiles = useMemo(() => {
+    const q = fileSearch.trim().toLowerCase();
+    if (!q) return files;
+    // Only search local files; keep provider files out of filtered results
+    return files.filter(f => !f.provider && f.name.toLowerCase().includes(q));
+  }, [files, fileSearch]);
+
   const handleFilesInputChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
     const files = e.target.files;
     if (files && files.length > 0) {
@@ -610,14 +624,37 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
               <span className={`text-xs ${isDark ? 'text-gray-500' : 'text-gray-500'}`}>Drag files here or click upload</span>
             </div>
 
-            {files.length === 0 ? (
+            <div className="flex items-center gap-2">
+              <input
+                value={fileSearch}
+                onChange={(e) => setFileSearch(e.target.value)}
+                className={`flex-1 text-sm border rounded px-2 py-1 ${isDark ? 'bg-gray-800 border-gray-700 text-gray-100 placeholder-gray-500' : 'bg-white border-gray-200 text-gray-800 placeholder-gray-400'}`}
+                placeholder="Search files by name..."
+              />
+              {fileSearch && (
+                <button
+                  onClick={() => setFileSearch('')}
+                  className={`text-xs px-2 py-1 rounded ${isDark ? 'bg-gray-800 border border-gray-700 text-gray-200' : 'bg-gray-100 border border-gray-200 text-gray-700'}`}
+                  title="Clear search"
+                >
+                  Clear
+                </button>
+              )}
+            </div>
+
+            {files.length === 0 && (uploadingFileIds?.length || 0) === 0 ? (
               <div className="flex flex-col items-center justify-center h-full opacity-50 border border-dashed border-gray-300 dark:border-gray-700 rounded">
                 <FileText size={32} className="mb-2" />
                 <p className="text-xs text-center">No files uploaded yet.</p>
               </div>
+            ) : filteredFiles.length === 0 && (uploadingFileIds?.length || 0) === 0 ? (
+              <div className="flex flex-col items-center justify-center h-full opacity-50 border border-dashed border-gray-300 dark:border-gray-700 rounded">
+                <FileText size={32} className="mb-2" />
+                <p className="text-xs text-center">No files match your search.</p>
+              </div>
             ) : (
               <div className="flex-1 overflow-y-auto space-y-1">
-                {files.map(f => (
+                {filteredFiles.map(f => (
                   <div
                     key={f.id}
                     className={`flex items-center justify-between px-2 py-1 rounded border ${isDark ? 'border-gray-700 hover:bg-gray-800' : 'border-gray-200 hover:bg-gray-100'}`}
@@ -627,6 +664,11 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
                       <span className={`text-[11px] ${isDark ? 'text-gray-500' : 'text-gray-500'}`}>
                         {formatSize(f.size)} • {new Date(f.created_at * 1000).toLocaleString()}
                       </span>
+                      {f.provider && (
+                        <span className={`text-[11px] inline-flex items-center gap-1 mt-0.5 px-2 py-0.5 rounded ${isDark ? 'bg-gray-800 text-gray-300 border border-gray-700' : 'bg-gray-100 text-gray-700 border border-gray-200'}`}>
+                          Provider: {f.provider === 'openai' ? 'OpenAI' : f.provider === 'google' ? 'Gemini' : f.provider}
+                        </span>
+                      )}
                     </div>
                     <div className="flex items-center gap-2">
                       <button
@@ -646,6 +688,14 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
                     </div>
                   </div>
                 ))}
+                {uploadingFileIds && uploadingFileIds.length > 0 && (
+                  <div className={`flex items-center justify-between px-2 py-2 rounded border border-dashed ${isDark ? 'border-gray-700 text-gray-400' : 'border-gray-300 text-gray-500'}`}>
+                    <div className="flex items-center gap-2">
+                      <Loader2 className="animate-spin" size={14} />
+                      <span className="text-sm">Uploading {uploadingFileIds.length} file{uploadingFileIds.length > 1 ? 's' : ''}…</span>
+                    </div>
+                  </div>
+                )}
               </div>
             )}
           </div>
-- 
cgit v1.2.3

