File size: 4,815 Bytes
5b7a2a5 3d2ab89 823f536 e39f16e c4c7362 d1d23d8 3d2ab89 5b7a2a5 050bf20 5b7a2a5 3d2ab89 6e3b5dc e39f16e 6e3b5dc e39f16e 5b7a2a5 6e3b5dc 5b7a2a5 e39f16e 5b7a2a5 823f536 6e3b5dc 5b7a2a5 823f536 5b7a2a5 e39f16e 5b7a2a5 e39f16e 5b7a2a5 e39f16e 5b7a2a5 11f93a8 ed9e18d 5b7a2a5 11f93a8 5b7a2a5 ed9e18d e39f16e 5b7a2a5 e39f16e 5b7a2a5 3d2ab89 5b7a2a5 3d2ab89 c4c7362 3d2ab89 d1d23d8 c4c7362 d1d23d8 c4c7362 5b7a2a5 3d2ab89 c4c7362 5b7a2a5 c4c7362 3d2ab89 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
import React, { useState } from 'react';
import type { Message } from 'ai';
import { toast } from 'react-toastify';
import { MAX_FILES, isBinaryFile, shouldIncludeFile } from '~/utils/fileUtils';
import { createChatFromFolder } from '~/utils/folderImport';
import { logStore } from '~/lib/stores/logs'; // Assuming logStore is imported from this location
import { Button } from '~/components/ui/Button';
import { classNames } from '~/utils/classNames';
interface ImportFolderButtonProps {
className?: string;
importChat?: (description: string, messages: Message[]) => Promise<void>;
}
export const ImportFolderButton: React.FC<ImportFolderButtonProps> = ({ className, importChat }) => {
const [isLoading, setIsLoading] = useState(false);
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const allFiles = Array.from(e.target.files || []);
const filteredFiles = allFiles.filter((file) => {
const path = file.webkitRelativePath.split('/').slice(1).join('/');
const include = shouldIncludeFile(path);
return include;
});
if (filteredFiles.length === 0) {
const error = new Error('No valid files found');
logStore.logError('File import failed - no valid files', error, { folderName: 'Unknown Folder' });
toast.error('No files found in the selected folder');
return;
}
if (filteredFiles.length > MAX_FILES) {
const error = new Error(`Too many files: ${filteredFiles.length}`);
logStore.logError('File import failed - too many files', error, {
fileCount: filteredFiles.length,
maxFiles: MAX_FILES,
});
toast.error(
`This folder contains ${filteredFiles.length.toLocaleString()} files. This product is not yet optimized for very large projects. Please select a folder with fewer than ${MAX_FILES.toLocaleString()} files.`,
);
return;
}
const folderName = filteredFiles[0]?.webkitRelativePath.split('/')[0] || 'Unknown Folder';
setIsLoading(true);
const loadingToast = toast.loading(`Importing ${folderName}...`);
try {
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) {
const error = new Error('No text files found');
logStore.logError('File import failed - no text files', error, { folderName });
toast.error('No text files found in the selected folder');
return;
}
if (binaryFilePaths.length > 0) {
logStore.logWarning(`Skipping binary files during import`, {
folderName,
binaryCount: binaryFilePaths.length,
});
toast.info(`Skipping ${binaryFilePaths.length} binary files`);
}
const messages = await createChatFromFolder(textFiles, binaryFilePaths, folderName);
if (importChat) {
await importChat(folderName, [...messages]);
}
logStore.logSystem('Folder imported successfully', {
folderName,
textFileCount: textFiles.length,
binaryFileCount: binaryFilePaths.length,
});
toast.success('Folder imported successfully');
} catch (error) {
logStore.logError('Failed to import folder', error, { folderName });
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
}
};
return (
<>
<input
type="file"
id="folder-import"
className="hidden"
webkitdirectory=""
directory=""
onChange={handleFileChange}
{...({} as any)}
/>
<Button
onClick={() => {
const input = document.getElementById('folder-import');
input?.click();
}}
title="Import Folder"
variant="outline"
size="lg"
className={classNames(
'gap-2 bg-[#F5F5F5] dark:bg-[#252525]',
'text-bolt-elements-textPrimary dark:text-white',
'hover:bg-[#E5E5E5] dark:hover:bg-[#333333]',
'border-[#E5E5E5] dark:border-[#333333]',
'h-10 px-4 py-2 min-w-[120px] justify-center',
'transition-all duration-200 ease-in-out',
className,
)}
disabled={isLoading}
>
<span className="i-ph:upload-simple w-4 h-4" />
{isLoading ? 'Importing...' : 'Import Folder'}
</Button>
</>
);
};
|