Remove import folder button (#92)

This commit is contained in:
Brian Hackett 2025-04-03 10:03:38 -07:00 committed by GitHub
parent a0303c1102
commit 6e5d09976e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 12 additions and 178 deletions

View File

@ -14,7 +14,6 @@ import { SendButton } from './SendButton.client';
import * as Tooltip from '@radix-ui/react-tooltip';
import styles from './BaseChat.module.scss';
import { ImportButtons } from '~/components/chat/chatExportAndImport/ImportButtons';
import { ExamplePrompts } from '~/components/chat/ExamplePrompts';
import FilePreview from './FilePreview';
@ -43,7 +42,6 @@ interface BaseChatProps {
handleInputChange?: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
_enhancingPrompt?: boolean;
_enhancePrompt?: () => void;
importChat?: (title: string, messages: Message[]) => Promise<void>;
uploadedFiles?: File[];
setUploadedFiles?: (files: File[]) => void;
imageDataList?: string[];
@ -69,7 +67,6 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
sendMessage,
handleStop,
importChat,
uploadedFiles = [],
setUploadedFiles,
imageDataList = [],
@ -470,7 +467,6 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
{!rejectFormOpen && messageInput}
</div>
</div>
{!chatStarted && <div className="flex justify-center gap-2">{ImportButtons(importChat)}</div>}
{!chatStarted &&
ExamplePrompts((event, messageInput) => {
if (hasPendingMessage) {

View File

@ -74,17 +74,12 @@ setInterval(async () => {
export function Chat() {
renderLogger.trace('Chat');
const { ready, initialMessages, resumeChat, storeMessageHistory, importChat } = useChatHistory();
const { ready, initialMessages, resumeChat, storeMessageHistory } = useChatHistory();
return (
<>
{ready && (
<ChatImpl
initialMessages={initialMessages}
resumeChat={resumeChat}
storeMessageHistory={storeMessageHistory}
importChat={importChat}
/>
<ChatImpl initialMessages={initialMessages} resumeChat={resumeChat} storeMessageHistory={storeMessageHistory} />
)}
<ToastContainer
closeButton={({ closeToast }) => {
@ -121,7 +116,6 @@ interface ChatProps {
initialMessages: Message[];
resumeChat: ResumeChatInfo | undefined;
storeMessageHistory: (messages: Message[]) => void;
importChat: (description: string, messages: Message[]) => Promise<void>;
}
let gNumAborts = 0;
@ -149,7 +143,7 @@ function mergeResponseMessage(msg: Message, messages: Message[]): Message[] {
}
export const ChatImpl = memo((props: ChatProps) => {
const { initialMessages, resumeChat: initialResumeChat, storeMessageHistory, importChat } = props;
const { initialMessages, resumeChat: initialResumeChat, storeMessageHistory } = props;
const textareaRef = useRef<HTMLTextAreaElement>(null);
const [chatStarted, setChatStarted] = useState(initialMessages.length > 0);
@ -616,7 +610,6 @@ export const ChatImpl = memo((props: ChatProps) => {
onTextareaChange(e);
}}
handleStop={abort}
importChat={importChat}
messages={messages}
uploadedFiles={uploadedFiles}
setUploadedFiles={setUploadedFiles}

View File

@ -1,132 +0,0 @@
import React, { useState } from 'react';
import { toast } from 'react-toastify';
import { MAX_FILES, isBinaryFile, shouldIncludeFile } from '~/utils/fileUtils';
import { createChatFromFolder, getFileRepositoryContents } from '~/utils/folderImport';
import { logStore } from '~/lib/stores/logs'; // Assuming logStore is imported from this location
import { createRepositoryImported } from '~/lib/replay/Repository';
import type { Message } from '~/lib/persistence/message';
interface ImportFolderButtonProps {
className?: string;
importChat?: (title: 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 repositoryContents = await getFileRepositoryContents(textFiles);
const repositoryId = await createRepositoryImported('ImportFolder', repositoryContents);
const messages = createChatFromFolder(folderName, repositoryId);
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();
}}
className={className}
disabled={isLoading}
>
<div className="i-ph:upload-simple" />
{isLoading ? 'Importing...' : 'Import Folder'}
</button>
</>
);
};

View File

@ -1,17 +0,0 @@
import { ImportFolderButton } from '~/components/chat/ImportFolderButton';
import type { Message } from '~/lib/persistence/message';
export function ImportButtons(importChat: ((description: string, messages: Message[]) => Promise<void>) | undefined) {
return (
<div className="flex flex-col items-center justify-center w-auto">
<div className="flex flex-col items-center gap-4 max-w-2xl text-center">
<div className="flex gap-2">
<ImportFolderButton
importChat={importChat}
className="px-4 py-2 rounded-lg border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary hover:bg-bolt-elements-background-depth-3 transition-all flex items-center gap-2"
/>
</div>
</div>
</div>
);
}

View File

@ -26,8 +26,8 @@ export function useChatHistory() {
const importChat = async (title: string, messages: Message[]) => {
try {
const newId = await database.createChat(title, messages);
window.location.href = `/chat/${newId}`;
const chat = await database.createChat(title, messages);
window.location.href = `/chat/${chat.id}`;
toast.success('Chat imported successfully');
} catch (error) {
if (error instanceof Error) {
@ -105,7 +105,6 @@ export function useChatHistory() {
debouncedSetChatContents(messages);
},
importChat,
};
}

View File

@ -8,15 +8,3 @@ export async function getRepositoryContents(repositoryId: string): Promise<strin
})) as { repositoryContents: string };
return rv.repositoryContents;
}
// Remotely create an imported repository from the given contents.
export async function createRepositoryImported(reason: string, repositoryContents: string): Promise<string> {
const rv = (await sendCommandDedicatedClient({
method: 'Nut.importRepository',
params: {
repositoryContents,
reason,
},
})) as { repositoryId: string };
return rv.repositoryId;
}

View File

@ -32,12 +32,19 @@ export async function initializeAuth() {
isLoadingStore.set(true);
// In local testing we've seen problems where Supabase auth hangs.
const timeout = setTimeout(() => {
console.error('Timed out initializing auth');
}, 5000);
// Get initial session
const {
data: { session },
error,
} = await getSupabase().auth.getSession();
clearTimeout(timeout);
if (error) {
throw error;
}