2024-11-26 08:18:46 +00:00
import React , { useState } from 'react' ;
2024-11-25 08:24:03 +00:00
import type { Message } from 'ai' ;
import { toast } from 'react-toastify' ;
2024-12-08 10:16:09 +00:00
import { MAX_FILES , isBinaryFile , shouldIncludeFile } from '~/utils/fileUtils' ;
import { createChatFromFolder } from '~/utils/folderImport' ;
2024-12-13 00:11:35 +00:00
import { logStore } from '~/lib/stores/logs' ; // Assuming logStore is imported from this location
2024-11-25 08:24:03 +00:00
interface ImportFolderButtonProps {
className? : string ;
importChat ? : ( description : string , messages : Message [ ] ) = > Promise < void > ;
}
export const ImportFolderButton : React.FC < ImportFolderButtonProps > = ( { className , importChat } ) = > {
2024-11-26 08:18:46 +00:00
const [ isLoading , setIsLoading ] = useState ( false ) ;
2024-11-25 17:50:01 +00:00
2024-11-26 08:18:46 +00:00
const handleFileChange = async ( e : React.ChangeEvent < HTMLInputElement > ) = > {
const allFiles = Array . from ( e . target . files || [ ] ) ;
2024-11-25 08:24:03 +00:00
2024-11-26 08:18:46 +00:00
if ( allFiles . length > MAX_FILES ) {
2024-12-13 00:11:35 +00:00
const error = new Error ( ` Too many files: ${ allFiles . length } ` ) ;
logStore . logError ( 'File import failed - too many files' , error , {
fileCount : allFiles.length ,
maxFiles : MAX_FILES ,
} ) ;
2024-11-26 08:18:46 +00:00
toast . error (
2024-12-08 10:16:09 +00:00
` This folder contains ${ allFiles . length . toLocaleString ( ) } files. This product is not yet optimized for very large projects. Please select a folder with fewer than ${ MAX_FILES . toLocaleString ( ) } files. ` ,
2024-11-26 08:18:46 +00:00
) ;
2024-12-13 00:11:35 +00:00
2024-11-26 08:18:46 +00:00
return ;
}
2024-12-08 10:16:09 +00:00
2024-11-26 08:18:46 +00:00
const folderName = allFiles [ 0 ] ? . webkitRelativePath . split ( '/' ) [ 0 ] || 'Unknown Folder' ;
setIsLoading ( true ) ;
2024-12-08 10:16:09 +00:00
2024-11-26 08:18:46 +00:00
const loadingToast = toast . loading ( ` Importing ${ folderName } ... ` ) ;
try {
const filteredFiles = allFiles . filter ( ( file ) = > shouldIncludeFile ( file . webkitRelativePath ) ) ;
if ( filteredFiles . length === 0 ) {
2024-12-13 00:11:35 +00:00
const error = new Error ( 'No valid files found' ) ;
logStore . logError ( 'File import failed - no valid files' , error , { folderName } ) ;
2024-11-26 08:18:46 +00:00
toast . error ( 'No files found in the selected folder' ) ;
2024-12-13 00:11:35 +00:00
2024-11-26 08:18:46 +00:00
return ;
}
const fileChecks = await Promise . all (
filteredFiles . map ( async ( file ) = > ( {
file ,
isBinary : await isBinaryFile ( file ) ,
} ) ) ,
) ;
const textFiles = fileChecks . filter ( ( f ) = > ! f . isBinary ) . map ( ( f ) = > f . file ) ;
const binaryFilePaths = fileChecks
. filter ( ( f ) = > f . isBinary )
. map ( ( f ) = > f . file . webkitRelativePath . split ( '/' ) . slice ( 1 ) . join ( '/' ) ) ;
if ( textFiles . length === 0 ) {
2024-12-13 00:11:35 +00:00
const error = new Error ( 'No text files found' ) ;
logStore . logError ( 'File import failed - no text files' , error , { folderName } ) ;
2024-11-26 08:18:46 +00:00
toast . error ( 'No text files found in the selected folder' ) ;
2024-12-13 00:11:35 +00:00
2024-11-26 08:18:46 +00:00
return ;
}
if ( binaryFilePaths . length > 0 ) {
2024-12-13 00:11:35 +00:00
logStore . logWarning ( ` Skipping binary files during import ` , {
folderName ,
binaryCount : binaryFilePaths.length ,
} ) ;
2024-11-26 08:18:46 +00:00
toast . info ( ` Skipping ${ binaryFilePaths . length } binary files ` ) ;
}
2024-12-07 22:42:29 +00:00
const messages = await createChatFromFolder ( textFiles , binaryFilePaths , folderName ) ;
2024-12-02 18:21:59 +00:00
2024-11-26 08:18:46 +00:00
if ( importChat ) {
2024-12-07 22:42:29 +00:00
await importChat ( folderName , [ . . . messages ] ) ;
2024-11-26 08:18:46 +00:00
}
2024-12-02 18:21:59 +00:00
2024-12-13 00:11:35 +00:00
logStore . logSystem ( 'Folder imported successfully' , {
folderName ,
textFileCount : textFiles.length ,
binaryFileCount : binaryFilePaths.length ,
} ) ;
2024-11-26 08:18:46 +00:00
toast . success ( 'Folder imported successfully' ) ;
} catch ( error ) {
2024-12-13 00:11:35 +00:00
logStore . logError ( 'Failed to import folder' , error , { folderName } ) ;
2024-11-26 08:18:46 +00:00
console . error ( 'Failed to import folder:' , error ) ;
toast . error ( 'Failed to import folder' ) ;
} finally {
setIsLoading ( false ) ;
toast . dismiss ( loadingToast ) ;
e . target . value = '' ; // Reset file input
2024-11-25 08:24:03 +00:00
}
} ;
return (
< >
< input
type = "file"
id = "folder-import"
className = "hidden"
webkitdirectory = ""
directory = ""
2024-11-26 08:18:46 +00:00
onChange = { handleFileChange }
{ . . . ( { } as any ) }
2024-11-25 08:24:03 +00:00
/ >
< button
onClick = { ( ) = > {
const input = document . getElementById ( 'folder-import' ) ;
input ? . click ( ) ;
} }
className = { className }
2024-11-26 08:18:46 +00:00
disabled = { isLoading }
2024-11-25 08:24:03 +00:00
>
2024-12-01 14:13:16 +00:00
< div className = "i-ph:upload-simple" / >
2024-11-26 08:18:46 +00:00
{ isLoading ? 'Importing...' : 'Import Folder' }
2024-11-25 08:24:03 +00:00
< / button >
< / >
) ;
} ;