diff options
| -rw-r--r-- | CLAUDE.md | 27 | ||||
| -rw-r--r-- | frontend/app/api/delete/route.ts | 67 | ||||
| -rw-r--r-- | frontend/components/drive/DriveDirectoryClient.tsx | 41 |
3 files changed, 99 insertions, 36 deletions
| @@ -46,30 +46,5 @@ | |||
| 46 | - **Updates**: Manual refresh only (no real-time) | 46 | - **Updates**: Manual refresh only (no real-time) |
| 47 | - the server is running at `127.0.0.1:3000` and you can use curl to test the page | 47 | - the server is running at `127.0.0.1:3000` and you can use curl to test the page |
| 48 | 48 | ||
| 49 | ## API Endpoints | 49 | ## HTTP Testing |
| 50 | |||
| 51 | ### Tree Endpoint | ||
| 52 | - `/api/tree` - GET filesystem tree with hierarchy | ||
| 53 | |||
| 54 | ### RESTful API - `/api/fs/[...path]` | ||
| 55 | - **GET** `/api/fs/path/to/directory` - List directory contents | ||
| 56 | - **POST** `/api/fs/path/to/directory` - Create directory | ||
| 57 | - **PUT** `/api/fs/path/to/file.txt` - Upload/create file | ||
| 58 | - **DELETE** `/api/fs/path/to/item` - Delete file or directory | ||
| 59 | |||
| 60 | ## API Testing | ||
| 61 | - For testing authenticated endpoints in development, use header `AUTH: 1` | 50 | - For testing authenticated endpoints in development, use header `AUTH: 1` |
| 62 | - Examples: | ||
| 63 | ```bash | ||
| 64 | # List directory | ||
| 65 | curl "http://localhost:3000/api/fs/some/directory" | ||
| 66 | |||
| 67 | # Create directory | ||
| 68 | curl -X POST "http://localhost:3000/api/fs/new_directory" -H "AUTH: 1" | ||
| 69 | |||
| 70 | # Upload file | ||
| 71 | curl -X PUT "http://localhost:3000/api/fs/path/file.txt" -H "AUTH: 1" -H "Content-Type: multipart/form-data" -F "file=@local_file.txt" | ||
| 72 | |||
| 73 | # Delete file/directory | ||
| 74 | curl -X DELETE "http://localhost:3000/api/fs/path/to/delete" -H "AUTH: 1" | ||
| 75 | ``` \ No newline at end of file | ||
diff --git a/frontend/app/api/delete/route.ts b/frontend/app/api/delete/route.ts new file mode 100644 index 0000000..31af119 --- /dev/null +++ b/frontend/app/api/delete/route.ts | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | import { NextRequest, NextResponse } from 'next/server' | ||
| 2 | import { Auth_get_user } from '@/lib/auth' | ||
| 3 | import { Drive_remove } from '@/lib/drive_server' | ||
| 4 | |||
| 5 | // DELETE /api/delete - Delete files/directories | ||
| 6 | export async function DELETE(request: NextRequest) { | ||
| 7 | try { | ||
| 8 | // Check user authentication | ||
| 9 | const user = await Auth_get_user() | ||
| 10 | if (!user.isLoggedIn) { | ||
| 11 | return NextResponse.json({ error: 'User not authenticated' }, { status: 401 }) | ||
| 12 | } | ||
| 13 | |||
| 14 | // Parse request body to get paths to delete | ||
| 15 | const body = await request.json() | ||
| 16 | const { paths } = body | ||
| 17 | |||
| 18 | if (!paths || !Array.isArray(paths) || paths.length === 0) { | ||
| 19 | return NextResponse.json({ error: 'No paths provided for deletion' }, { status: 400 }) | ||
| 20 | } | ||
| 21 | |||
| 22 | // Validate paths (basic sanitation) | ||
| 23 | for (const path of paths) { | ||
| 24 | if (typeof path !== 'string' || path.trim() === '') { | ||
| 25 | return NextResponse.json({ error: 'Invalid path provided' }, { status: 400 }) | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | const results = [] | ||
| 30 | const errors = [] | ||
| 31 | |||
| 32 | // Delete each path using Drive_remove | ||
| 33 | for (const path of paths) { | ||
| 34 | try { | ||
| 35 | await Drive_remove(path, user.email) | ||
| 36 | results.push({ path, success: true }) | ||
| 37 | } catch (error) { | ||
| 38 | console.error(`Failed to delete ${path}:`, error) | ||
| 39 | errors.push({ | ||
| 40 | path, | ||
| 41 | error: error instanceof Error ? error.message : 'Unknown error' | ||
| 42 | }) | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | // Return results | ||
| 47 | const response = { | ||
| 48 | success: errors.length === 0, | ||
| 49 | message: errors.length === 0 | ||
| 50 | ? `Successfully deleted ${results.length} item(s)` | ||
| 51 | : `Deleted ${results.length} item(s), failed to delete ${errors.length} item(s)`, | ||
| 52 | results, | ||
| 53 | errors | ||
| 54 | } | ||
| 55 | |||
| 56 | return NextResponse.json(response, { | ||
| 57 | status: errors.length === 0 ? 200 : 207 // 207 Multi-Status for partial success | ||
| 58 | }) | ||
| 59 | |||
| 60 | } catch (error) { | ||
| 61 | console.error('Delete API error:', error) | ||
| 62 | return NextResponse.json( | ||
| 63 | { error: error instanceof Error ? error.message : 'Internal server error' }, | ||
| 64 | { status: 500 } | ||
| 65 | ) | ||
| 66 | } | ||
| 67 | } \ No newline at end of file | ||
diff --git a/frontend/components/drive/DriveDirectoryClient.tsx b/frontend/components/drive/DriveDirectoryClient.tsx index c3c23a7..4657141 100644 --- a/frontend/components/drive/DriveDirectoryClient.tsx +++ b/frontend/components/drive/DriveDirectoryClient.tsx | |||
| @@ -234,16 +234,37 @@ export function DriveDirectoryClient({ path, files, breadcrumbs }: DriveDirector | |||
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | const handleDelete = async (itemPaths: string[]) => { | 236 | const handleDelete = async (itemPaths: string[]) => { |
| 237 | // TODO: Implement actual delete API calls | 237 | try { |
| 238 | setSelectedFiles(new Set()) | 238 | const response = await fetch('/api/delete', { |
| 239 | 239 | method: 'DELETE', | |
| 240 | toast({ | 240 | headers: { |
| 241 | title: "Deleted successfully", | 241 | 'Content-Type': 'application/json', |
| 242 | description: `${itemPaths.length} item(s) deleted`, | 242 | }, |
| 243 | }) | 243 | body: JSON.stringify({ paths: itemPaths }) |
| 244 | 244 | }) | |
| 245 | // Refresh page to show changes | 245 | |
| 246 | window.location.reload() | 246 | const result = await response.json() |
| 247 | |||
| 248 | if (response.ok) { | ||
| 249 | setSelectedFiles(new Set()) | ||
| 250 | toast({ | ||
| 251 | title: "Deleted successfully", | ||
| 252 | description: result.message, | ||
| 253 | }) | ||
| 254 | |||
| 255 | // Refresh page to show changes | ||
| 256 | window.location.reload() | ||
| 257 | } else { | ||
| 258 | throw new Error(result.error || `Delete failed with status ${response.status}`) | ||
| 259 | } | ||
| 260 | } catch (error) { | ||
| 261 | console.error('Delete error:', error) | ||
| 262 | toast({ | ||
| 263 | title: "Delete failed", | ||
| 264 | description: error instanceof Error ? error.message : 'Unknown error occurred', | ||
| 265 | variant: "destructive" | ||
| 266 | }) | ||
| 267 | } | ||
| 247 | } | 268 | } |
| 248 | 269 | ||
| 249 | const handleLogin = () => { | 270 | const handleLogin = () => { |
