Skip to content

Commit

Permalink
add download button for projects directory in UI
Browse files Browse the repository at this point in the history
  • Loading branch information
bigsk1 committed Jul 19, 2024
1 parent e34285a commit 35a1f73
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 7 deletions.
30 changes: 29 additions & 1 deletion backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
import subprocess
import platform
import shutil
import tempfile
from starlette.background import BackgroundTask
import uvicorn
from fastapi import FastAPI, APIRouter, UploadFile, File, HTTPException, Request, Query
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse, JSONResponse
from fastapi.responses import StreamingResponse, JSONResponse, FileResponse
from pydantic import BaseModel
from dotenv import load_dotenv
from automode_logic import AutomodeRequest, start_automode_logic
Expand Down Expand Up @@ -109,6 +111,7 @@ class DirectoryContents(BaseModel):
automode_progress = 0
automode_messages = []


@app.post("/automode")
async def start_automode(request: Request):
automode_request = AutomodeRequest(**await request.json())
Expand Down Expand Up @@ -358,6 +361,31 @@ async def chat(request: ChatRequest):
logger.error(f"Error in chat endpoint: {str(e)}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))

@api_router.get("/download_projects")
async def download_projects():
if not os.path.exists(PROJECTS_DIR):
raise HTTPException(status_code=404, detail="Projects directory not found")

temp_dir = tempfile.mkdtemp()
try:
zip_filename = "projects.zip"
zip_path = os.path.join(temp_dir, zip_filename)

shutil.make_archive(zip_path[:-4], 'zip', PROJECTS_DIR)

return FileResponse(
path=zip_path,
filename=zip_filename,
media_type='application/zip',
background=BackgroundTask(cleanup, temp_dir)
)
except Exception as e:
shutil.rmtree(temp_dir, ignore_errors=True)
raise HTTPException(status_code=500, detail=f"Error creating zip file: {str(e)}")

def cleanup(temp_dir: str):
shutil.rmtree(temp_dir, ignore_errors=True)

def get_shell():
return "cmd.exe" if platform.system() == "Windows" else "/bin/bash"

Expand Down
60 changes: 54 additions & 6 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
Box, VStack, HStack, Button, Input, useColorMode,
Tabs, TabList, TabPanels, Tab, TabPanel, Text, Modal, ModalOverlay, ModalContent,
ModalHeader, ModalFooter, ModalBody, ModalCloseButton, useDisclosure, Flex, IconButton,
Menu, MenuButton, MenuList, MenuItem, InputGroup, Progress, Textarea, Checkbox
Menu, MenuButton, MenuList, MenuItem, InputGroup, Progress, Textarea, Checkbox, useToast
} from '@chakra-ui/react';
import { SunIcon, MoonIcon, ChevronDownIcon, AddIcon, DeleteIcon } from '@chakra-ui/icons';
import { FaFolder, FaFile, FaImage } from 'react-icons/fa';
Expand All @@ -13,6 +13,7 @@ import { ChakraProvider } from '@chakra-ui/react';
import ReactDiffViewer from 'react-diff-viewer-continued';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { atomDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
import { FaDownload } from 'react-icons/fa';

import theme from './theme';
import './App.css';
Expand Down Expand Up @@ -52,6 +53,7 @@ function App() {
const { isOpen, onOpen, onClose } = useDisclosure();
const [isLoading, setIsLoading] = useState(false);
const messagesEndRef = useRef<HTMLDivElement>(null);
const toast = useToast();

useEffect(() => {
listFiles(currentDirectory);
Expand Down Expand Up @@ -346,6 +348,44 @@ function App() {
}
};

const handleDownloadProjects = async () => {
try {
const response = await axios.get(`${API_URL}/api/download_projects`, {
responseType: 'blob',
timeout: 30000 // 30 seconds timeout
});

const blob = new Blob([response.data], { type: 'application/zip' });
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'projects.zip');
document.body.appendChild(link);
link.click();
if (link.parentNode) {
link.parentNode.removeChild(link);
}
window.URL.revokeObjectURL(url);

toast({
title: "Download Started",
description: "Your projects folder is being downloaded.",
status: "success",
duration: 3000,
isClosable: true,
});
} catch (error) {
console.error('Error downloading projects:', error);
toast({
title: "Download Failed",
description: "There was an error downloading the projects folder. Please try again.",
status: "error",
duration: 5000,
isClosable: true,
});
}
};

const customComponents: Components = {
code({ inline, className, children, ...props }: CodeProps) {
const match = /language-(\w+)/.exec(className || '');
Expand All @@ -371,11 +411,19 @@ function App() {
<Flex direction="column" minHeight="100vh" width="100%" className={colorMode === 'dark' ? 'dark-mode' : 'light-mode'}>
<Flex as="header" width="100%" justifyContent="space-between" alignItems="center" p={4} bg={colorMode === 'dark' ? 'gray.700' : 'gray.100'}>
<Text fontSize="2xl" fontWeight="bold">Claude Plus</Text>
<IconButton
icon={colorMode === 'light' ? <MoonIcon /> : <SunIcon />}
onClick={toggleColorMode}
aria-label="Toggle color mode"
/>
<HStack spacing={4}>
<IconButton
icon={<FaDownload />}
onClick={handleDownloadProjects}
aria-label="Download Projects"
title="Download Projects Folder"
/>
<IconButton
icon={colorMode === 'light' ? <MoonIcon /> : <SunIcon />}
onClick={toggleColorMode}
aria-label="Toggle color mode"
/>
</HStack>
</Flex>
<Flex direction="column" flex={1} p={4} alignItems="center" bg={colorMode === 'dark' ? 'gray.800' : 'white'} color={colorMode === 'dark' ? 'white' : 'gray.800'}>
<Box width="100%" maxWidth="1200px">
Expand Down

0 comments on commit 35a1f73

Please sign in to comment.