Merge remote-tracking branch 'origin/feature/new-project-creation' into feature/new-project-creation

This commit is contained in:
simos
2025-11-04 09:32:42 +00:00
3 changed files with 122 additions and 19 deletions

View File

@@ -251,7 +251,12 @@ router.post('/create-workspace', async (req, res) => {
await cloneGitHubRepository(githubUrl, absolutePath, githubToken);
} catch (error) {
// Clean up created directory on failure
await fs.rm(absolutePath, { recursive: true, force: true });
try {
await fs.rm(absolutePath, { recursive: true, force: true });
} catch (cleanupError) {
console.error('Failed to clean up directory after clone failure:', cleanupError);
// Continue to throw original error
}
throw new Error(`Failed to clone repository: ${error.message}`);
}
}

View File

@@ -1,9 +1,63 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import { Button } from './ui/button';
import { X } from 'lucide-react';
function ImageViewer({ file, onClose }) {
const imagePath = `/api/projects/${file.projectName}/files/content?path=${encodeURIComponent(file.path)}`;
const [imageUrl, setImageUrl] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let objectUrl;
const controller = new AbortController();
const loadImage = async () => {
try {
setLoading(true);
setError(null);
setImageUrl(null);
const token = localStorage.getItem('auth-token');
if (!token) {
setError('Missing authentication token');
return;
}
const response = await fetch(imagePath, {
headers: {
'Authorization': `Bearer ${token}`
},
signal: controller.signal
});
if (!response.ok) {
throw new Error(`Request failed with status ${response.status}`);
}
const blob = await response.blob();
objectUrl = URL.createObjectURL(blob);
setImageUrl(objectUrl);
} catch (err) {
if (err.name === 'AbortError') {
return;
}
console.error('Error loading image:', err);
setError('Unable to load image');
} finally {
setLoading(false);
}
};
loadImage();
return () => {
controller.abort();
if (objectUrl) {
URL.revokeObjectURL(objectUrl);
}
};
}, [imagePath]);
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@@ -23,22 +77,24 @@ function ImageViewer({ file, onClose }) {
</div>
<div className="p-4 flex justify-center items-center bg-gray-50 dark:bg-gray-900 min-h-[400px]">
<img
src={imagePath}
alt={file.name}
className="max-w-full max-h-[70vh] object-contain rounded-lg shadow-md"
onError={(e) => {
e.target.style.display = 'none';
e.target.nextSibling.style.display = 'block';
}}
/>
<div
className="text-center text-gray-500 dark:text-gray-400"
style={{ display: 'none' }}
>
<p>Unable to load image</p>
<p className="text-sm mt-2">{file.path}</p>
</div>
{loading && (
<div className="text-center text-gray-500 dark:text-gray-400">
<p>Loading image</p>
</div>
)}
{!loading && imageUrl && (
<img
src={imageUrl}
alt={file.name}
className="max-w-full max-h-[70vh] object-contain rounded-lg shadow-md"
/>
)}
{!loading && !imageUrl && (
<div className="text-center text-gray-500 dark:text-gray-400">
<p>{error || 'Unable to load image'}</p>
<p className="text-sm mt-2 break-all">{file.path}</p>
</div>
)}
</div>
<div className="p-4 border-t bg-gray-50 dark:bg-gray-800">
@@ -51,4 +107,4 @@ function ImageViewer({ file, onClose }) {
);
}
export default ImageViewer;
export default ImageViewer;

View File

@@ -344,6 +344,48 @@ function Sidebar({
}
};
const createNewProject = async () => {
if (!newProjectPath.trim()) {
alert('Please enter a project path');
return;
}
setCreatingProject(true);
try {
const response = await api.createProject(newProjectPath.trim());
if (response.ok) {
const result = await response.json();
// Save the path to recent paths before clearing
saveToRecentPaths(newProjectPath.trim());
setShowNewProject(false);
setNewProjectPath('');
// Refresh projects to show the new one
if (window.refreshProjects) {
window.refreshProjects();
} else {
window.location.reload();
}
} else {
const error = await response.json();
alert(error.error || 'Failed to create project. Please try again.');
}
} catch (error) {
console.error('Error creating project:', error);
alert('Error creating project. Please try again.');
} finally {
setCreatingProject(false);
}
};
const cancelNewProject = () => {
setShowNewProject(false);
setNewProjectPath('');
};
const loadMoreSessions = async (project) => {
// Check if we can load more sessions