mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
Remove import folder button (#92)
This commit is contained in:
parent
a0303c1102
commit
6e5d09976e
@ -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) {
|
||||
|
@ -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}
|
||||
|
@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
@ -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>
|
||||
);
|
||||
}
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user